@actiondock/core 2.14.0 → 2.15.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.
@@ -1,4 +1,4 @@
1
- import type { ActionDockManifest } from "../project/types.js";
1
+ import type { ActionDockManifest, PlaybookSourceManifest } from "../project/types.js";
2
2
  import type { PackageIdentity } from "../runtime/identity.js";
3
3
  /**
4
4
  * 发现的包基本信息规范。
@@ -8,8 +8,8 @@ export interface DiscoveredPackage {
8
8
  readonly id: string;
9
9
  /** 包物理根目录绝对路径 */
10
10
  readonly root: string;
11
- /** 包清单定义 */
12
- readonly manifest: ActionDockManifest;
11
+ /** 包清单定义(支持磁盘声明式清单与运行时规程来源清单) */
12
+ readonly manifest: ActionDockManifest | PlaybookSourceManifest;
13
13
  /** 包物理与快照身份凭证(可选,由已有运行时传入) */
14
14
  readonly identity?: PackageIdentity;
15
15
  /** 是否来自工作区目录扫描发现 */
@@ -1,6 +1,6 @@
1
1
  import { ActionDockError } from "../errors.js";
2
2
  import { type ActionDockLockfile } from "../project/lockfile.js";
3
- import type { ActionDockManifest, PlaybookDefinition } from "../project/types.js";
3
+ import type { ActionDockManifest, PlaybookDefinition, PlaybookSourceManifest } from "../project/types.js";
4
4
  import { type PackageIdentity } from "../runtime/identity.js";
5
5
  import { parseSemVer, type SemVer } from "../utils/index.js";
6
6
  import { type DiscoveredPackage, type PackageDiscoveryOptions } from "./discovery.js";
@@ -51,8 +51,8 @@ export interface PackageNode {
51
51
  readonly packageId: string;
52
52
  /** 包根目录绝对物理路径 */
53
53
  readonly root: string;
54
- /** 包清单规范 */
55
- readonly manifest: ActionDockManifest;
54
+ /** 包清单规范(支持磁盘声明式清单与运行时规程来源清单) */
55
+ readonly manifest: ActionDockManifest | PlaybookSourceManifest;
56
56
  /** 包清单摘要哈希 */
57
57
  readonly manifestDigest: string;
58
58
  /** 包版本号 */
@@ -148,7 +148,7 @@ export interface PackageGraphBuilderOptions {
148
148
  /** 当前工程根目录绝对或相对物理路径 */
149
149
  projectRoot?: string;
150
150
  /** 显式根清单 */
151
- manifest?: ActionDockManifest;
151
+ manifest?: ActionDockManifest | PlaybookSourceManifest;
152
152
  /** 锁文件规范对象(若未显式提供且 projectRoot 存在,则尝试自动读取 actiondock.lock.json) */
153
153
  lockfile?: ActionDockLockfile;
154
154
  /** 是否允许扫描与链接开发软链接包(默认根据 discoveryOptions 判定) */
@@ -321,30 +321,20 @@ function computeTransitiveDependencies(nodes) {
321
321
  function collectVisiblePlaybooks(rootNode, nodes) {
322
322
  const visiblePlaybooks = new Map();
323
323
  const delegatedActions = new Set();
324
- if (rootNode && rootNode.root && existsSync(rootNode.root)) {
325
- try {
326
- const rootPbs = loadPlaybooks(rootNode.root, undefined, rootNode.manifest);
327
- for (const [id, pb] of rootPbs.entries()) {
328
- visiblePlaybooks.set(id, pb);
329
- visiblePlaybooks.set(`${rootNode.packageId}/${id}`, pb);
330
- }
331
- }
332
- catch {
333
- // 忽略根包 Playbook 加载异常
324
+ if (rootNode) {
325
+ const rootPbs = loadPlaybooks(rootNode.root || "", undefined, rootNode.manifest);
326
+ for (const [id, pb] of rootPbs.entries()) {
327
+ visiblePlaybooks.set(id, pb);
328
+ visiblePlaybooks.set(`${rootNode.packageId}/${id}`, pb);
334
329
  }
335
330
  for (const depId of rootNode.directDependencies) {
336
331
  if (depId === rootNode.packageId)
337
332
  continue;
338
333
  const depNode = nodes.get(depId);
339
- if (depNode && depNode.root && existsSync(depNode.root)) {
340
- try {
341
- const depPbs = loadPlaybooks(depNode.root, undefined, depNode.manifest);
342
- for (const [id, pb] of depPbs.entries()) {
343
- visiblePlaybooks.set(`${depId}/${id}`, pb);
344
- }
345
- }
346
- catch {
347
- // 忽略依赖包 Playbook 加载异常
334
+ if (depNode) {
335
+ const depPbs = loadPlaybooks(depNode.root || "", undefined, depNode.manifest);
336
+ for (const [id, pb] of depPbs.entries()) {
337
+ visiblePlaybooks.set(`${depId}/${id}`, pb);
348
338
  }
349
339
  }
350
340
  }
@@ -383,7 +373,7 @@ export class PackageGraphBuilder {
383
373
  manifest: pkg.manifest,
384
374
  npmPackage: pkg.id,
385
375
  isDirect: Boolean(pkg.isCurrentProject),
386
- isRoot: Boolean(pkg.isCurrentProject),
376
+ isRoot: false,
387
377
  identity: pkg.identity,
388
378
  generation,
389
379
  });
@@ -405,19 +395,14 @@ export class PackageGraphBuilder {
405
395
  }
406
396
  }
407
397
  if (!rootIdentity) {
408
- for (const node of nodes.values()) {
409
- if (node.isRoot) {
410
- rootIdentity = node.identity;
411
- break;
412
- }
398
+ const currentProjectNodes = Array.from(nodes.values()).filter((n) => n.isDirect);
399
+ if (currentProjectNodes.length === 1) {
400
+ rootIdentity = currentProjectNodes[0].identity;
413
401
  }
414
402
  }
415
- if (rootIdentity) {
416
- const rootNode = nodes.get(rootIdentity.id);
417
- if (rootNode) {
418
- rootNode.isRoot = true;
419
- rootNode.isDirect = true;
420
- }
403
+ for (const [id, node] of nodes) {
404
+ const isTheRoot = Boolean(rootIdentity && node.identity.id === rootIdentity.id);
405
+ nodes.set(id, { ...node, isRoot: isTheRoot, isDirect: isTheRoot || Boolean(node.isDirect) });
421
406
  }
422
407
  if (this.options.validateDependencies) {
423
408
  for (const node of nodes.values()) {
@@ -20,7 +20,7 @@ export interface ResolvePlaybookContext {
20
20
  readonly caller?: string;
21
21
  }
22
22
  /**
23
- * 纯领域规程解析函数 resolvePlaybook。
24
- * 基于 PackageGraph 替代原 registry 内部的 resolvePlaybookProject 启发式搜索。
23
+ * 基于 PackageGraph 的规程寻址函数,正文统一由规程加载层提供。
24
+ * 替代原 registry 内部的 resolvePlaybookProject 启发式搜索。
25
25
  */
26
26
  export declare function resolvePlaybook(identifier: string, context: ResolvePlaybookContext): ResolvedPlaybook;
@@ -1,48 +1,12 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { resolve } from "node:path";
3
1
  import { loadPlaybooks } from "../project/loader.js";
4
2
  import { getPackageSlug } from "../utils/index.js";
5
3
  import { ActionDockError, INVALID_ACTION_REF, NOT_FOUND, PACKAGE_NOT_FOUND } from "../errors.js";
6
4
  function getNodePlaybooks(node) {
7
- const map = new Map();
8
- if (node.root && existsSync(node.root)) {
9
- try {
10
- const diskPlaybooks = loadPlaybooks(node.root, node.manifest?.playbooksDir);
11
- for (const [k, v] of diskPlaybooks) {
12
- map.set(k, v);
13
- }
14
- }
15
- catch {
16
- // 忽略磁盘规程目录扫描异常
17
- }
18
- }
19
- if (node.manifest?.playbooks && typeof node.manifest.playbooks === "object") {
20
- for (const [id, item] of Object.entries(node.manifest.playbooks)) {
21
- const existing = map.get(id);
22
- let content = item.content ?? existing?.content ?? "";
23
- let filePath = item.entry && node.root
24
- ? resolve(node.root, item.entry)
25
- : existing?.filePath;
26
- if (!content && filePath && existsSync(filePath)) {
27
- try {
28
- content = readFileSync(filePath, "utf-8");
29
- }
30
- catch { }
31
- }
32
- map.set(id, {
33
- id,
34
- description: item.description ?? existing?.description,
35
- actions: item.actions ?? existing?.actions ?? [],
36
- content,
37
- filePath: filePath || "",
38
- });
39
- }
40
- }
41
- return map;
5
+ return loadPlaybooks(node.root, node.manifest.playbooksDir, node.manifest);
42
6
  }
43
7
  /**
44
- * 纯领域规程解析函数 resolvePlaybook。
45
- * 基于 PackageGraph 替代原 registry 内部的 resolvePlaybookProject 启发式搜索。
8
+ * 基于 PackageGraph 的规程寻址函数,正文统一由规程加载层提供。
9
+ * 替代原 registry 内部的 resolvePlaybookProject 启发式搜索。
46
10
  */
47
11
  export function resolvePlaybook(identifier, context) {
48
12
  const str = identifier.trim();
@@ -87,20 +51,15 @@ export function resolvePlaybook(identifier, context) {
87
51
  // 3. 全局搜索
88
52
  const matches = [];
89
53
  for (const node of context.graph.packages.values()) {
90
- try {
91
- const playbooks = getNodePlaybooks(node);
92
- const pb = playbooks.get(str);
93
- if (pb) {
94
- matches.push({
95
- packageId: node.identity.id,
96
- projectRoot: node.root,
97
- playbookId: str,
98
- playbook: pb,
99
- });
100
- }
101
- }
102
- catch {
103
- // 忽略单个包加载异常
54
+ const playbooks = getNodePlaybooks(node);
55
+ const pb = playbooks.get(str);
56
+ if (pb) {
57
+ matches.push({
58
+ packageId: node.identity.id,
59
+ projectRoot: node.root,
60
+ playbookId: str,
61
+ playbook: pb,
62
+ });
104
63
  }
105
64
  }
106
65
  if (matches.length === 1) {
@@ -1,5 +1,5 @@
1
1
  import type { ActionDefinition, ActionRef, ExecutionEvent, ExecutionResult, JsonValue, Logger, ProcessAPI, RunRecord, RunStatus } from "@actiondock/sdk";
2
- import type { ProjectConfig } from "../project/types.js";
2
+ import type { ProjectConfig, RuntimeProjectConfig } from "../project/types.js";
3
3
  import type { Clock } from "../storage/clock.js";
4
4
  import type { EventSink } from "../runtime/events.js";
5
5
  import type { RuntimeStorage } from "../storage/types.js";
@@ -40,7 +40,7 @@ export interface ExecutionServiceOptions {
40
40
  storage: RuntimeStorage;
41
41
  globalStorage?: RuntimeStorage;
42
42
  projectRoot?: string;
43
- projectConfig?: ProjectConfig;
43
+ projectConfig?: ProjectConfig | RuntimeProjectConfig;
44
44
  configOverrides?: Record<string, unknown>;
45
45
  actions?: Map<string, ActionDefinition>;
46
46
  process?: ProcessAPI;
@@ -25,7 +25,7 @@ export declare function listVisiblePlaybooks(runtimes: readonly PackageRuntime[]
25
25
  graph?: PackageGraph;
26
26
  }): Promise<PlaybookSummary[]>;
27
27
  /**
28
- * 静态查询指定 Playbook 规范:基于 resolvePlaybook 统一纯领域解析。
28
+ * 静态查询指定 Playbook 规范:委托 resolvePlaybook 统一寻址与来源加载。
29
29
  */
30
30
  export declare function describeVisiblePlaybook(runtimes: readonly PackageRuntime[], id: string, visibility: {
31
31
  hostPublicPackageIds: ReadonlySet<string>;
@@ -83,7 +83,7 @@ function buildFallbackGraph(runtimes) {
83
83
  ])));
84
84
  }
85
85
  /**
86
- * 静态查询指定 Playbook 规范:基于 resolvePlaybook 统一纯领域解析。
86
+ * 静态查询指定 Playbook 规范:委托 resolvePlaybook 统一寻址与来源加载。
87
87
  */
88
88
  export async function describeVisiblePlaybook(runtimes, id, visibility) {
89
89
  const graph = visibility.graph || buildFallbackGraph(runtimes);
package/dist/index.d.ts CHANGED
@@ -22,8 +22,8 @@ export { startActionDockServer, } from "./server/server.js";
22
22
  export type { ServerOptions, ServerOptions as ActionDockServerOptions, ActionDockServerInstance, } from "./server/types.js";
23
23
  export { initProject } from "./project/init.js";
24
24
  export { loadProjectConfig, findProjectRoot, } from "./project/loader.js";
25
- export { inspectLocalPackageDirectory, validateLocalSkillPackages, isExplicitPath, } from "./project/skill-dir.js";
26
- export type { ProjectConfig, } from "./project/types.js";
25
+ export { discoverLocalSkillDirectory, inspectLocalPackageDirectory, queryLocalPackageDirectory, validateLocalSkillPackages, isExplicitPath, } from "./project/skill-dir.js";
26
+ export type { ProjectConfig, PlaybookSourceManifest, RuntimeProjectConfig, } from "./project/types.js";
27
27
  export type { LocalSkillDirectory, LocalPackageEntry, } from "./project/skill-dir.js";
28
28
  export type { PackageGraph, } from "./catalog/graph.js";
29
29
  export { ActionDockError, ProcessError, PACKAGE_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_NOT_FOUND, ACTION_LOAD_FAILED, ACTION_FAILED, ACTION_TIMEOUT, ACTION_CANCELLED, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, ACTION_CALL_CYCLE, UNDECLARED_ACTION_DEPENDENCY, INVALID_ACTION_REF, IDEMPOTENCY_CONFLICT, EXECUTION_FAILED, UNHANDLED_EXECUTION_ERROR, RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, STANDALONE_ASYNC_UNSUPPORTED, HOST_PROCESS_EXITED, EXECUTION_ABORTED, TIMEOUT, NETWORK_ERROR, CAPABILITY_UNAVAILABLE, STATE_KEY_NOT_FOUND, STORAGE_BUSY, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, EVENT_BACKPRESSURE_LIMIT, EVENT_CURSOR_EXPIRED, PROCESS_OUTPUT_LIMIT, PROCESS_SPAWN_ERROR, PROCESS_CANCELLED, PROCESS_TIMEOUT, UNAUTHORIZED, NOT_FOUND, SERVER_ERROR, PACKAGE_FORBIDDEN, ACTION_FORBIDDEN, PLAYBOOK_NOT_FOUND, REQUEST_TOO_LARGE, ACTION_START_FAILED, ACTION_EXECUTION_ERROR, DATA_DIR_IN_USE, DATA_DIR_RECOVERY_REQUIRED, PROCESS_FAILED, MCP_TOOL_NAME_COLLISION, ACCESS_DENIED, INVALID_FLAT_ARGUMENT, INVALID_JSON, INVALID_JSON_LITERAL, INPUT_PATH_CONFLICT, FLAT_INPUT_LIMIT_EXCEEDED, INPUT_LIMIT_EXCEEDED, INPUT_POLICY_VIOLATION, INPUT_CONFLICT, INPUT_FILE_NOT_FOUND, INPUT_FILE_READ_FAILED, INVALID_ARGUMENT, PACKAGE_NOT_ALLOWED, INVALID_PACKAGE_ID, PATH_TRAVERSAL, AMBIGUOUS_STATE_KEY, RUN_NOT_FOUND, RUN_ALREADY_FINISHED, PROJECT_ROOT_NOT_FOUND, describeActionLoadFailure, createErrorEnvelope, resolveExecutionHint, } from "./errors.js";
package/dist/index.js CHANGED
@@ -19,6 +19,6 @@ export { startActionDockServer, } from "./server/server.js";
19
19
  // 6. 核心工程辅助
20
20
  export { initProject } from "./project/init.js";
21
21
  export { loadProjectConfig, findProjectRoot, } from "./project/loader.js";
22
- export { inspectLocalPackageDirectory, validateLocalSkillPackages, isExplicitPath, } from "./project/skill-dir.js";
22
+ export { discoverLocalSkillDirectory, inspectLocalPackageDirectory, queryLocalPackageDirectory, validateLocalSkillPackages, isExplicitPath, } from "./project/skill-dir.js";
23
23
  // 8. 统一错误模型与核心标准错误码常量
24
24
  export { ActionDockError, ProcessError, PACKAGE_NOT_FOUND, ACTION_PACKAGE_VERSION_CONFLICT, ACTION_NOT_FOUND, ACTION_LOAD_FAILED, ACTION_FAILED, ACTION_TIMEOUT, ACTION_CANCELLED, INPUT_VALIDATION_FAILED, OUTPUT_VALIDATION_FAILED, INPUT_NOT_JSON, OUTPUT_NOT_JSON, ACTION_SUBRUN_LIMIT, ACTION_CALL_CYCLE, UNDECLARED_ACTION_DEPENDENCY, INVALID_ACTION_REF, IDEMPOTENCY_CONFLICT, EXECUTION_FAILED, UNHANDLED_EXECUTION_ERROR, RUN_REPOSITORY_UNAVAILABLE, RUN_PERSISTENCE_FAILED, STANDALONE_ASYNC_UNSUPPORTED, HOST_PROCESS_EXITED, EXECUTION_ABORTED, TIMEOUT, NETWORK_ERROR, CAPABILITY_UNAVAILABLE, STATE_KEY_NOT_FOUND, STORAGE_BUSY, PROJECT_BUSY, PROJECT_RECOVERY_REQUIRED, EVENT_BACKPRESSURE_LIMIT, EVENT_CURSOR_EXPIRED, PROCESS_OUTPUT_LIMIT, PROCESS_SPAWN_ERROR, PROCESS_CANCELLED, PROCESS_TIMEOUT, UNAUTHORIZED, NOT_FOUND, SERVER_ERROR, PACKAGE_FORBIDDEN, ACTION_FORBIDDEN, PLAYBOOK_NOT_FOUND, REQUEST_TOO_LARGE, ACTION_START_FAILED, ACTION_EXECUTION_ERROR, DATA_DIR_IN_USE, DATA_DIR_RECOVERY_REQUIRED, PROCESS_FAILED, MCP_TOOL_NAME_COLLISION, ACCESS_DENIED, INVALID_FLAT_ARGUMENT, INVALID_JSON, INVALID_JSON_LITERAL, INPUT_PATH_CONFLICT, FLAT_INPUT_LIMIT_EXCEEDED, INPUT_LIMIT_EXCEEDED, INPUT_POLICY_VIOLATION, INPUT_CONFLICT, INPUT_FILE_NOT_FOUND, INPUT_FILE_READ_FAILED, INVALID_ARGUMENT, PACKAGE_NOT_ALLOWED, INVALID_PACKAGE_ID, PATH_TRAVERSAL, AMBIGUOUS_STATE_KEY, RUN_NOT_FOUND, RUN_ALREADY_FINISHED, PROJECT_ROOT_NOT_FOUND, describeActionLoadFailure, createErrorEnvelope, resolveExecutionHint, } from "./errors.js";
@@ -1,6 +1,6 @@
1
1
  import type { ExecutionEvent, ExecutionResult, JsonValue, RunRecord } from "@actiondock/sdk";
2
2
  import type { ActionInvoker, CancelResult, ExecutionTicket } from "../execution/types.js";
3
- import type { ProjectConfig } from "../project/types.js";
3
+ import type { ProjectConfig, RuntimeProjectConfig } from "../project/types.js";
4
4
  import { type PackageIdentity } from "../runtime/identity.js";
5
5
  import { type InvocationContext, type RunOptions } from "../invocation/types.js";
6
6
  import type { ActionSpec, ActionSummary, ConfigValueView, HostManagedPackageRuntime, ListActionsOptions, ListRunsOptions, PackageInfo, PackageRuntime, PackageRuntimeOptions, PackageRuntimeInternalOptions, PlaybookSpec, PlaybookSummary, StateScopeOptions } from "./types.js";
@@ -21,7 +21,7 @@ export declare class DefaultPackageRuntime implements HostManagedPackageRuntime
21
21
  readonly packageInstanceId: string;
22
22
  readonly generationId: string;
23
23
  readonly packageRoot?: string;
24
- readonly projectConfig: ProjectConfig;
24
+ readonly projectConfig: ProjectConfig | RuntimeProjectConfig;
25
25
  readonly inMemory: boolean;
26
26
  private readonly platform;
27
27
  private readonly actionsMap;
@@ -2,7 +2,7 @@ import { existsSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { DefaultExecutionService } from "../execution/service.js";
4
4
  import { createNodePlatform } from "../platform/index.js";
5
- import { findProjectRoot, loadProjectConfig } from "../project/loader.js";
5
+ import { completeRuntimeProjectConfig, findProjectRoot, loadProjectConfig } from "../project/loader.js";
6
6
  import { RuntimeConfig } from "../runtime/context.js";
7
7
  import { normalizeActionCollection } from "../runtime/action-collection.js";
8
8
  import { isSecretConfigKey, sanitizeConfigDefinitions } from "../storage/mask.js";
@@ -125,6 +125,8 @@ export class DefaultPackageRuntime {
125
125
  version: "0.1.0",
126
126
  };
127
127
  }
128
+ // 在唯一装配边界确定规程来源,索引与包图共享同一份完整配置快照。
129
+ projectConfig = completeRuntimeProjectConfig(packageRoot, projectConfig);
128
130
  this.packageRoot = packageRoot;
129
131
  this.projectConfig = projectConfig;
130
132
  // 兼容未在公开选项契约中显式声明的包实例标识与代系标识内部参数透传
@@ -1,5 +1,5 @@
1
1
  import type { ActionDefinition } from "@actiondock/sdk";
2
- import type { ProjectConfig } from "../project/types.js";
2
+ import type { ProjectConfig, RuntimeProjectConfig } from "../project/types.js";
3
3
  import type { ActionSpec, PlaybookSpec } from "./types.js";
4
4
  /**
5
5
  * 静态清单索引构建入参:同一包的全部静态事实来源。
@@ -10,8 +10,8 @@ export interface StaticIndexInput {
10
10
  packageRoot?: string;
11
11
  /** 包唯一标识 */
12
12
  packageId: string;
13
- /** 项目配置(规范化清单配置快照,单一事实源) */
14
- projectConfig: ProjectConfig;
13
+ /** 项目配置(规范化清单配置快照或运行时来源,单一事实源) */
14
+ projectConfig: ProjectConfig | RuntimeProjectConfig;
15
15
  }
16
16
  /** Action 索引构建入参:静态事实来源之上叠加内存注入的 Action 定义集合 */
17
17
  export interface StaticActionIndexInput extends StaticIndexInput {
@@ -29,8 +29,6 @@ export interface StaticActionIndexInput extends StaticIndexInput {
29
29
  export declare function buildStaticActionMap(input: StaticActionIndexInput): Map<string, ActionSpec>;
30
30
  /**
31
31
  * 静态读取并聚合指定包的 Playbook 规范索引。
32
- *
33
- * 聚合来源:磁盘规程目录扫描(以 actiondock.json 声明为事实源)与
34
- * 项目配置中声明的 playbooks;同键时配置声明覆盖磁盘扫描结果。
32
+ * 统一复用 project/loader 的 loadPlaybooks(单一事实源),不再自行读文件或吞异常。
35
33
  */
36
34
  export declare function buildStaticPlaybookMap(input: StaticIndexInput): Map<string, PlaybookSpec>;
@@ -1,7 +1,5 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join, resolve } from "node:path";
1
+ import { resolve } from "node:path";
3
2
  import { loadPlaybooks } from "../project/loader.js";
4
- import { MANIFEST_FILE_NAME } from "../project/manifest.js";
5
3
  /**
6
4
  * 将增量声明合并到既有 Action 规范之上(纯函数,单一事实源)。
7
5
  *
@@ -86,67 +84,21 @@ export function buildStaticActionMap(input) {
86
84
  }
87
85
  /**
88
86
  * 静态读取并聚合指定包的 Playbook 规范索引。
89
- *
90
- * 聚合来源:磁盘规程目录扫描(以 actiondock.json 声明为事实源)与
91
- * 项目配置中声明的 playbooks;同键时配置声明覆盖磁盘扫描结果。
87
+ * 统一复用 project/loader 的 loadPlaybooks(单一事实源),不再自行读文件或吞异常。
92
88
  */
93
89
  export function buildStaticPlaybookMap(input) {
94
90
  const { packageRoot, packageId, projectConfig } = input;
95
91
  const map = new Map();
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
- }
92
+ const loaded = loadPlaybooks(packageRoot || "", projectConfig.playbooksDir, projectConfig);
93
+ for (const [id, def] of loaded) {
94
+ map.set(id, {
95
+ id: def.id,
96
+ packageId,
97
+ description: def.description,
98
+ actions: def.actions,
99
+ content: def.content,
100
+ filePath: def.filePath,
101
+ });
150
102
  }
151
103
  return map;
152
104
  }
@@ -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 } from "../project/types.js";
4
+ import type { ConfigItemDefinition, ProjectConfig, RuntimeProjectConfig } 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 | RuntimeProjectConfig;
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 | RuntimeProjectConfig;
246
246
  /** 是否采用纯内存运行模式 */
247
247
  readonly inMemory?: boolean;
248
248
  /**
@@ -86,10 +86,10 @@ export function initProject(targetDir, options = {}) {
86
86
  node: ">=24.12.0",
87
87
  },
88
88
  dependencies: {
89
- "@actiondock/sdk": "^2.14.0",
89
+ "@actiondock/sdk": "^2.15.0",
90
90
  },
91
91
  devDependencies: {
92
- "@actiondock/testing": "^2.14.0",
92
+ "@actiondock/testing": "^2.15.0",
93
93
  "@types/node": "^22.13.0",
94
94
  "tsx": "^4.19.0",
95
95
  "typescript": "^5.7.0",
@@ -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, ProjectConfig } from "./types.js";
3
+ import type { ActionDockManifest, PlaybookDefinition, PlaybookManifestEntry, PlaybookSourceManifest, ProjectConfig, RuntimeProjectConfig } from "./types.js";
4
4
  /**
5
5
  * 从指定目录开始向上逐级递归查找包含 `actiondock.json` 的项目根目录。
6
6
  *
@@ -16,6 +16,8 @@ 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;
19
21
  export declare const ALLOWED_INSTALLERS: Set<string>;
20
22
  /**
21
23
  * 探测宿主系统中可用的包管理工具。
@@ -71,4 +73,4 @@ export declare function parsePlaybookContent(content: string, filePath: string,
71
73
  * @param customManifest 可选的显式清单对象(若未提供则从磁盘加载)
72
74
  * @returns Map<PlaybookId, PlaybookDefinition> 映射
73
75
  */
74
- export declare function loadPlaybooks(projectRoot: string, _playbooksDir?: string, customManifest?: ActionDockManifest | null): Map<string, PlaybookDefinition>;
76
+ export declare function loadPlaybooks(projectRoot: string, _playbooksDir?: string, customManifest?: ActionDockManifest | PlaybookSourceManifest | null): Map<string, PlaybookDefinition>;
@@ -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, ACTION_ID_REGEX, PLAYBOOK_ID_REGEX } from "./manifest.js";
6
+ import { loadManifest, normalizeFilePlaybookEntries, 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 parsed;
71
+ return normalizeFilePlaybookEntries(parsed);
72
72
  }
73
73
  catch (err) {
74
74
  if (err instanceof ActionDockError) {
@@ -77,6 +77,15 @@ 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
+ }
80
89
  export const ALLOWED_INSTALLERS = new Set(["npm", "bun"]);
81
90
  /**
82
91
  * 异步探测包管理器可用性(通过执行 --version 并检查退出码)。
@@ -308,43 +317,38 @@ export function parsePlaybookContent(content, filePath, metadata) {
308
317
  */
309
318
  export function loadPlaybooks(projectRoot, _playbooksDir = "playbooks", customManifest) {
310
319
  const playbooks = new Map();
311
- let manifest = null;
312
- if (customManifest !== undefined) {
313
- manifest = customManifest;
314
- }
315
- else {
316
- try {
317
- manifest = loadManifest(projectRoot);
320
+ const isExplicitSource = customManifest !== undefined;
321
+ const manifest = isExplicitSource
322
+ ? customManifest
323
+ : projectRoot ? loadManifest(projectRoot) : null;
324
+ for (const [playbookId, entry] of Object.entries(manifest?.playbooks || {})) {
325
+ if (!PLAYBOOK_ID_REGEX.test(playbookId)) {
326
+ throw new ActionDockError(INVALID_PLAYBOOK_ID, `Invalid playbook ID '${playbookId}' in manifest. Playbook IDs must match ${PLAYBOOK_ID_REGEX}`);
318
327
  }
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;
328
+ let content;
329
+ let filePath;
330
+ if (isExplicitSource && "content" in entry && typeof entry.content === "string") {
331
+ // 真实内联来源(包括空字符串)无需访问磁盘。
332
+ content = entry.content;
333
+ filePath = entry.entry ? (projectRoot ? resolve(projectRoot, entry.entry) : entry.entry) : "";
326
334
  }
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}`);
335
+ else {
336
+ if (!entry.entry || typeof entry.entry !== "string") {
337
+ throw new ActionDockError(PLAYBOOK_NOT_FOUND, `Playbook entry for '${playbookId}' must specify a valid file path or explicit inline content`);
333
338
  }
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}`);
339
+ filePath = resolve(projectRoot, entry.entry);
340
+ assertPathWithinRoot(projectRoot, filePath, `playbook entry '${entry.entry}'`);
341
+ if (!existsSync(filePath)) {
342
+ throw new ActionDockError(PLAYBOOK_NOT_FOUND, `Playbook file '${entry.entry}' for '${playbookId}' not found in ${projectRoot}`);
338
343
  }
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);
344
+ content = readFileSync(filePath, "utf-8");
347
345
  }
346
+ playbooks.set(playbookId, parsePlaybookContent(content, filePath, {
347
+ id: playbookId,
348
+ name: entry.name,
349
+ description: entry.description,
350
+ actions: entry.actions,
351
+ }));
348
352
  }
349
353
  return playbooks;
350
354
  }
@@ -2,6 +2,8 @@ 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;
5
7
  /**
6
8
  * 读取并解析项目的声明式清单文件(actiondock.json 为唯一事实源)。
7
9
  * 若文件不存在则返回 null。
@@ -5,6 +5,22 @@ 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
+ }
8
24
  /**
9
25
  * 读取并解析项目的声明式清单文件(actiondock.json 为唯一事实源)。
10
26
  * 若文件不存在则返回 null。
@@ -38,7 +54,7 @@ export function loadManifest(projectRoot) {
38
54
  if (!parsed.id) {
39
55
  parsed.id = basename(projectRoot);
40
56
  }
41
- return parsed;
57
+ return normalizeFilePlaybookEntries(parsed);
42
58
  }
43
59
  /**
44
60
  * 保存声明式清单文件至项目根目录(actiondock.json)。
@@ -1,6 +1,6 @@
1
1
  import type { ProjectConfig } from "./types.js";
2
2
  /**
3
- * 本地封闭包条目。
3
+ * 本地包条目;是否构成封闭集合由校验入口保证。
4
4
  */
5
5
  export interface LocalPackageEntry {
6
6
  packageId: string;
@@ -8,7 +8,7 @@ export interface LocalPackageEntry {
8
8
  projectConfig: ProjectConfig;
9
9
  }
10
10
  /**
11
- * 本地技能 / 包目录发现视图。
11
+ * 本地技能 / 包目录发现视图,不代表已经通过封闭集合校验。
12
12
  */
13
13
  export interface LocalSkillDirectory {
14
14
  type: "single" | "composite";
@@ -39,11 +39,27 @@ export declare function validateLocalSkillPackages(packages: Array<{
39
39
  packageRoot: string;
40
40
  projectConfig: ProjectConfig;
41
41
  }>): void;
42
+ /**
43
+ * 发现本地 Skill / 包目录结构(支持单包根目录与 packages/* 复合套件布局)。
44
+ * 仅执行物理布局发现与清单加载,不执行跨包封闭依赖集合校验。
45
+ *
46
+ * @param directoryPath 待检查的目录路径(相对路径将基于 cwd 解析)
47
+ * @param cwd 解析基准工作目录(默认为 process.cwd())
48
+ */
49
+ export declare function discoverLocalSkillDirectory(directoryPath: string, cwd?: string): LocalSkillDirectory | null;
50
+ /**
51
+ * 查询指定路径的本地包或技能目录(供 info / 查询命令使用)。
52
+ * 单包不要求 node_modules 依赖闭包;复合目录仍要求封闭集合完整。
53
+ *
54
+ * @param directoryPath 待检查的目录路径(相对路径将基于 cwd 解析)
55
+ * @param cwd 解析基准工作目录(默认为 process.cwd())
56
+ */
57
+ export declare function queryLocalPackageDirectory(directoryPath: string, cwd?: string): LocalSkillDirectory | null;
42
58
  /**
43
59
  * 探测指定路径是否为本地 Skill / 包目录(支持单包根目录与 packages/* 复合套件布局)。
44
60
  *
45
61
  * 封闭包装配与校验规则:
46
- * - 边界安全防护:packages 目录、各子包目录与 actiondock.json 清单真实路径必须在 Skill 根边界内,禁止越界符号链接;
62
+ * - 符号链接按目录布局正常解析;Action 与规程入口的文件边界由相应加载器校验;
47
63
  * - 单包布局:目录根部存在 actiondock.json,解析为包含单一包的 LocalSkillDirectory;
48
64
  * - 复合布局:目录根部存在 packages/ 目录,遍历其直接子目录,收集包含 actiondock.json 的子包;
49
65
  * - 集合一致性校验:通过 validateLocalSkillPackages 严格核查依赖闭包、版本兼容与 uses 目标;
@@ -124,20 +124,13 @@ export function validateLocalSkillPackages(packages) {
124
124
  }
125
125
  }
126
126
  /**
127
- * 探测指定路径是否为本地 Skill / 包目录(支持单包根目录与 packages/* 复合套件布局)。
128
- *
129
- * 封闭包装配与校验规则:
130
- * - 边界安全防护:packages 目录、各子包目录与 actiondock.json 清单真实路径必须在 Skill 根边界内,禁止越界符号链接;
131
- * - 单包布局:目录根部存在 actiondock.json,解析为包含单一包的 LocalSkillDirectory;
132
- * - 复合布局:目录根部存在 packages/ 目录,遍历其直接子目录,收集包含 actiondock.json 的子包;
133
- * - 集合一致性校验:通过 validateLocalSkillPackages 严格核查依赖闭包、版本兼容与 uses 目标;
134
- * - 异常透传:坏清单或权限异常原样抛出,严禁静默回退 Registry;
135
- * - 若非候选技能目录,返回 null。
127
+ * 发现本地 Skill / 包目录结构(支持单包根目录与 packages/* 复合套件布局)。
128
+ * 仅执行物理布局发现与清单加载,不执行跨包封闭依赖集合校验。
136
129
  *
137
130
  * @param directoryPath 待检查的目录路径(相对路径将基于 cwd 解析)
138
131
  * @param cwd 解析基准工作目录(默认为 process.cwd())
139
132
  */
140
- export function inspectLocalPackageDirectory(directoryPath, cwd) {
133
+ export function discoverLocalSkillDirectory(directoryPath, cwd) {
141
134
  if (!directoryPath || typeof directoryPath !== "string") {
142
135
  return null;
143
136
  }
@@ -165,7 +158,6 @@ export function inspectLocalPackageDirectory(directoryPath, cwd) {
165
158
  projectConfig: config,
166
159
  },
167
160
  ];
168
- validateLocalSkillPackages(packages);
169
161
  return {
170
162
  type: "single",
171
163
  root: absDir,
@@ -201,7 +193,6 @@ export function inspectLocalPackageDirectory(directoryPath, cwd) {
201
193
  }
202
194
  }
203
195
  if (packages.length > 0) {
204
- validateLocalSkillPackages(packages);
205
196
  return {
206
197
  type: "composite",
207
198
  root: absDir,
@@ -212,3 +203,42 @@ export function inspectLocalPackageDirectory(directoryPath, cwd) {
212
203
  }
213
204
  return null;
214
205
  }
206
+ /**
207
+ * 查询指定路径的本地包或技能目录(供 info / 查询命令使用)。
208
+ * 单包不要求 node_modules 依赖闭包;复合目录仍要求封闭集合完整。
209
+ *
210
+ * @param directoryPath 待检查的目录路径(相对路径将基于 cwd 解析)
211
+ * @param cwd 解析基准工作目录(默认为 process.cwd())
212
+ */
213
+ export function queryLocalPackageDirectory(directoryPath, cwd) {
214
+ const discovered = discoverLocalSkillDirectory(directoryPath, cwd);
215
+ if (!discovered) {
216
+ return null;
217
+ }
218
+ if (discovered.type === "composite") {
219
+ validateLocalSkillPackages(discovered.packages);
220
+ }
221
+ return discovered;
222
+ }
223
+ /**
224
+ * 探测指定路径是否为本地 Skill / 包目录(支持单包根目录与 packages/* 复合套件布局)。
225
+ *
226
+ * 封闭包装配与校验规则:
227
+ * - 符号链接按目录布局正常解析;Action 与规程入口的文件边界由相应加载器校验;
228
+ * - 单包布局:目录根部存在 actiondock.json,解析为包含单一包的 LocalSkillDirectory;
229
+ * - 复合布局:目录根部存在 packages/ 目录,遍历其直接子目录,收集包含 actiondock.json 的子包;
230
+ * - 集合一致性校验:通过 validateLocalSkillPackages 严格核查依赖闭包、版本兼容与 uses 目标;
231
+ * - 异常透传:坏清单或权限异常原样抛出,严禁静默回退 Registry;
232
+ * - 若非候选技能目录,返回 null。
233
+ *
234
+ * @param directoryPath 待检查的目录路径(相对路径将基于 cwd 解析)
235
+ * @param cwd 解析基准工作目录(默认为 process.cwd())
236
+ */
237
+ export function inspectLocalPackageDirectory(directoryPath, cwd) {
238
+ const discovered = discoverLocalSkillDirectory(directoryPath, cwd);
239
+ if (!discovered) {
240
+ return null;
241
+ }
242
+ validateLocalSkillPackages(discovered.packages);
243
+ return discovered;
244
+ }
@@ -53,6 +53,25 @@ 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;
56
75
  /**
57
76
  * ActionDock 声明式元数据清单契约(actiondock.json 为唯一事实源)。
58
77
  */
@@ -93,10 +112,20 @@ export interface ActionDockManifest {
93
112
  [key: string]: unknown;
94
113
  };
95
114
  }
115
+ /**
116
+ * 内存运行时或图模型中支持内联正文的规程来源清单契约。
117
+ */
118
+ export type PlaybookSourceManifest = Omit<ActionDockManifest, "playbooks"> & {
119
+ playbooks?: Record<string, PlaybookSourceEntry>;
120
+ };
96
121
  /**
97
122
  * ActionDock 项目根配置文件契约(等同于 ActionDockManifest,actiondock.json 为单一事实源)。
98
123
  */
99
124
  export type ProjectConfig = ActionDockManifest;
125
+ /**
126
+ * 内存运行时或图模型中支持内联正文的项目配置契约。
127
+ */
128
+ export type RuntimeProjectConfig = PlaybookSourceManifest;
100
129
  /**
101
130
  * 解析后的完整 Playbook 定义对象。
102
131
  */
@@ -1,5 +1,5 @@
1
1
  import type { ActionContext, ActionRef, Config, Logger, ProcessAPI, ProgressReporter, StateStore } from "@actiondock/sdk";
2
- import type { ProjectConfig } from "../project/types.js";
2
+ import type { ProjectConfig, RuntimeProjectConfig } 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, globalStorage?: RuntimeStorage);
20
+ constructor(storage: RuntimeStorage, overrides?: Record<string, unknown>, projectConfig?: ProjectConfig | RuntimeProjectConfig, 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 | RuntimeProjectConfig;
74
74
  parentRunId?: string;
75
75
  runId?: string;
76
76
  rootRunId?: string;
package/dist/version.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * ActionDock 核心版本号单一事实源。
3
3
  */
4
- export declare const ACTIONDOCK_VERSION = "2.14.0";
4
+ export declare const ACTIONDOCK_VERSION = "2.15.0";
package/dist/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * ActionDock 核心版本号单一事实源。
3
3
  */
4
- export const ACTIONDOCK_VERSION = "2.14.0";
4
+ export const ACTIONDOCK_VERSION = "2.15.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actiondock/core",
3
- "version": "2.14.0",
3
+ "version": "2.15.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.14.0",
62
+ "@actiondock/sdk": "^2.15.0",
63
63
  "ajv": "^8.17.1",
64
64
  "ajv-formats": "^3.0.1",
65
65
  "undici": "^7.29.1"