@actiondock/core 2.0.11 → 2.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/build/templates.d.ts +19 -0
  2. package/dist/catalog/action-index.d.ts +9 -0
  3. package/dist/catalog/action-resolver.d.ts +20 -0
  4. package/dist/catalog/location-registry.d.ts +15 -0
  5. package/dist/catalog/package-catalog.d.ts +7 -0
  6. package/dist/catalog/types.d.ts +68 -0
  7. package/dist/doctor/doctor.d.ts +6 -0
  8. package/dist/doctor/types.d.ts +23 -0
  9. package/dist/execution/index.d.ts +2 -0
  10. package/dist/execution/service.d.ts +74 -0
  11. package/dist/execution/types.d.ts +74 -0
  12. package/dist/export/templates.d.ts +33 -0
  13. package/dist/filter/intent.d.ts +33 -0
  14. package/{src/index.ts → dist/index.d.ts} +1 -1
  15. package/dist/index.js +8458 -0
  16. package/dist/profile/client.d.ts +116 -0
  17. package/dist/profile/manager.d.ts +47 -0
  18. package/dist/profile/types.d.ts +61 -0
  19. package/dist/project/closure.d.ts +25 -0
  20. package/{src/project/index.ts → dist/project/index.d.ts} +1 -0
  21. package/dist/project/init.d.ts +27 -0
  22. package/dist/project/loader.d.ts +105 -0
  23. package/dist/project/manifest.d.ts +44 -0
  24. package/dist/project/types.d.ts +131 -0
  25. package/dist/registry/registry.d.ts +24 -0
  26. package/dist/registry/types.d.ts +117 -0
  27. package/dist/runtime/clock.d.ts +21 -0
  28. package/dist/runtime/context.d.ts +75 -0
  29. package/dist/runtime/env.d.ts +54 -0
  30. package/dist/runtime/events.d.ts +61 -0
  31. package/dist/runtime/execution-manager.d.ts +48 -0
  32. package/{src/runtime/index.ts → dist/runtime/index.d.ts} +0 -1
  33. package/dist/runtime/module-loader.d.ts +42 -0
  34. package/dist/runtime/process.d.ts +11 -0
  35. package/dist/runtime/runner.d.ts +186 -0
  36. package/dist/runtime/standalone.d.ts +40 -0
  37. package/dist/schema/validator.d.ts +28 -0
  38. package/dist/server/body.d.ts +40 -0
  39. package/{src/server/index.ts → dist/server/index.d.ts} +0 -1
  40. package/dist/server/routes/actions.d.ts +5 -0
  41. package/dist/server/routes/common.d.ts +36 -0
  42. package/dist/server/routes/config.d.ts +5 -0
  43. package/dist/server/routes/doctor.d.ts +5 -0
  44. package/dist/server/routes/health.d.ts +5 -0
  45. package/dist/server/routes/info.d.ts +5 -0
  46. package/dist/server/routes/playbooks.d.ts +5 -0
  47. package/dist/server/routes/runs.d.ts +5 -0
  48. package/dist/server/routes/state.d.ts +5 -0
  49. package/dist/server/runtime-registry.d.ts +78 -0
  50. package/dist/server/security.d.ts +37 -0
  51. package/dist/server/server.d.ts +15 -0
  52. package/dist/server/types.d.ts +59 -0
  53. package/dist/storage/driver.d.ts +15 -0
  54. package/dist/storage/index.d.ts +44 -0
  55. package/{src/storage/mask.ts → dist/storage/mask.d.ts} +5 -20
  56. package/dist/storage/sqlite.d.ts +66 -0
  57. package/dist/storage/types.d.ts +121 -0
  58. package/dist/utils/index.d.ts +29 -0
  59. package/dist/version.d.ts +4 -0
  60. package/package.json +11 -10
  61. package/src/build/templates.ts +0 -59
  62. package/src/catalog/action-index.ts +0 -92
  63. package/src/catalog/action-resolver.ts +0 -120
  64. package/src/catalog/location-registry.ts +0 -134
  65. package/src/catalog/package-catalog.ts +0 -87
  66. package/src/catalog/types.ts +0 -75
  67. package/src/doctor/doctor.ts +0 -419
  68. package/src/doctor/types.ts +0 -25
  69. package/src/execution/index.ts +0 -2
  70. package/src/execution/service.ts +0 -322
  71. package/src/execution/types.ts +0 -73
  72. package/src/export/templates.ts +0 -590
  73. package/src/filter/intent.ts +0 -154
  74. package/src/profile/client.ts +0 -552
  75. package/src/profile/manager.ts +0 -341
  76. package/src/profile/types.ts +0 -71
  77. package/src/project/init.ts +0 -242
  78. package/src/project/loader.ts +0 -479
  79. package/src/project/manifest.ts +0 -299
  80. package/src/project/types.ts +0 -141
  81. package/src/registry/registry.ts +0 -940
  82. package/src/registry/types.ts +0 -127
  83. package/src/runtime/clock.ts +0 -41
  84. package/src/runtime/context.ts +0 -259
  85. package/src/runtime/env.ts +0 -172
  86. package/src/runtime/events.ts +0 -142
  87. package/src/runtime/execution-manager.ts +0 -74
  88. package/src/runtime/module-loader.ts +0 -67
  89. package/src/runtime/process.ts +0 -245
  90. package/src/runtime/runner.ts +0 -527
  91. package/src/runtime/standalone.ts +0 -429
  92. package/src/schema/validator.ts +0 -61
  93. package/src/server/body.ts +0 -112
  94. package/src/server/routes/actions.ts +0 -262
  95. package/src/server/routes/common.ts +0 -126
  96. package/src/server/routes/config.ts +0 -147
  97. package/src/server/routes/doctor.ts +0 -29
  98. package/src/server/routes/health.ts +0 -40
  99. package/src/server/routes/info.ts +0 -221
  100. package/src/server/routes/playbooks.ts +0 -109
  101. package/src/server/routes/runs.ts +0 -301
  102. package/src/server/routes/state.ts +0 -133
  103. package/src/server/runtime-registry.ts +0 -115
  104. package/src/server/security.ts +0 -115
  105. package/src/server/server.ts +0 -251
  106. package/src/server/types.ts +0 -57
  107. package/src/storage/driver.ts +0 -126
  108. package/src/storage/index.ts +0 -81
  109. package/src/storage/sqlite.ts +0 -714
  110. package/src/storage/types.ts +0 -139
  111. package/src/utils/index.ts +0 -62
  112. /package/{src/build/index.ts → dist/build/index.d.ts} +0 -0
  113. /package/{src/catalog/index.ts → dist/catalog/index.d.ts} +0 -0
  114. /package/{src/doctor/index.ts → dist/doctor/index.d.ts} +0 -0
  115. /package/{src/export/index.ts → dist/export/index.d.ts} +0 -0
  116. /package/{src/filter/index.ts → dist/filter/index.d.ts} +0 -0
  117. /package/{src/profile/index.ts → dist/profile/index.d.ts} +0 -0
  118. /package/{src/registry/index.ts → dist/registry/index.d.ts} +0 -0
  119. /package/{src/server/routes/index.ts → dist/server/routes/index.d.ts} +0 -0
@@ -0,0 +1,29 @@
1
+ export { findExecutable } from "@actiondock/sdk";
2
+ /**
3
+ * Parses duration strings like "500ms", "30s", "5m", "1h", "1d" or pure numbers into milliseconds.
4
+ */
5
+ export declare function parseDuration(input?: string): number | undefined;
6
+ /**
7
+ * Extracts a concise slug from a package or action identifier (e.g. '@scope/pkg' -> 'pkg', 'team.action' -> 'action').
8
+ */
9
+ export declare function getPackageSlug(id: string): string;
10
+ /**
11
+ * Resolves the root ActionDock user home directory based on customHome, ACTIONDOCK_HOME, or user homedir.
12
+ */
13
+ export declare function getActionDockHome(customHome?: string): string;
14
+ export declare const PACKAGE_ID_REGEX: RegExp;
15
+ /**
16
+ * Validates packageId to ensure it adheres to valid naming conventions and prevents path traversal.
17
+ */
18
+ export declare function assertValidPackageId(packageId: string): void;
19
+ /**
20
+ * Ensures that a given path stays strictly within the specified root boundary,
21
+ * preventing relative directory escape (..) and symlink jailbreak.
22
+ * Traverses upward to the nearest existing ancestor directory to resolve symlinks
23
+ * even for non-existent paths.
24
+ */
25
+ export declare function assertPathWithinRoot(rootDir: string, targetPath: string, fieldName?: string): void;
26
+ /**
27
+ * Backwards-compatible alias for assertPathWithinRoot targeting project roots.
28
+ */
29
+ export declare function assertWithinProjectRoot(projectRoot: string, subDir: string, fieldName: string): void;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * ActionDock 核心版本号单一事实源。
3
+ */
4
+ export declare const ACTIONDOCK_VERSION = "2.0.12";
package/package.json CHANGED
@@ -1,39 +1,40 @@
1
1
  {
2
2
  "name": "@actiondock/core",
3
- "version": "2.0.11",
3
+ "version": "2.0.12",
4
4
  "description": "ActionDock Core Engine - Project loader, runtime execution, SQLite storage, standalone builder, and skill exporter",
5
5
  "type": "module",
6
- "main": "./src/index.ts",
7
- "module": "./src/index.ts",
8
- "types": "./src/index.ts",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "import": "./src/index.ts",
12
- "types": "./src/index.ts"
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
13
14
  }
14
15
  },
15
16
  "files": [
16
- "src",
17
+ "dist",
17
18
  "README.md"
18
19
  ],
19
20
  "engines": {
20
- "node": ">=22.12.0"
21
+ "node": ">=22.13.0"
21
22
  },
22
23
  "publishConfig": {
23
24
  "access": "public",
24
25
  "registry": "https://registry.npmjs.org/"
25
26
  },
26
27
  "scripts": {
28
+ "build": "bun run ../../scripts/build.ts",
27
29
  "test": "bun test"
28
30
  },
29
31
  "dependencies": {
30
- "@actiondock/sdk": "^2.0.11",
32
+ "@actiondock/sdk": "^2.0.12",
31
33
  "ajv": "^8.17.1",
32
34
  "ajv-formats": "^3.0.1",
33
35
  "yaml": "^2.7.0"
34
36
  },
35
37
  "devDependencies": {
36
- "@types/bun": "latest",
37
38
  "typescript": "^5.7.0"
38
39
  },
39
40
  "keywords": [
@@ -1,59 +0,0 @@
1
- import { resolve } from "node:path";
2
-
3
- /**
4
- * 构建时 Action 导入映射。
5
- */
6
- export interface ActionImport {
7
- /** Action 唯一标识符 */
8
- id: string;
9
- /** Action 源码文件物理路径 */
10
- filePath: string;
11
- }
12
-
13
- /**
14
- * 动态生成 Standalone 独立可执行文件的 TypeScript 入口文件源码。
15
- *
16
- * @param packageId 所属 Package ID
17
- * @param version 版本号
18
- * @param description 描述
19
- * @param actions 待打包 Action 列表
20
- * @param configDefs 声明的配置定义字典
21
- */
22
- export function generateStandaloneEntrypoint(
23
- packageId: string,
24
- version: string,
25
- description: string | undefined,
26
- actions: ActionImport[],
27
- configDefs?: Record<string, unknown>
28
- ): string {
29
- // Resolve path to standalone runtime inside @actiondock/cli
30
- const standaloneRuntimePath = resolve(import.meta.dirname, "../runtime/standalone");
31
-
32
- const imports = actions
33
- .map((a, idx) => `import action_${idx} from ${JSON.stringify(a.filePath)};`)
34
- .join("\n");
35
-
36
- const actionArray = actions
37
- .map((_, idx) => `action_${idx}`)
38
- .join(",\n ");
39
-
40
- return `// AUTO-GENERATED ENTRYPOINT BY ACTIONDOCK BUILDER. DO NOT EDIT.
41
- import { createStandaloneRuntime } from ${JSON.stringify(standaloneRuntimePath)};
42
- ${imports}
43
-
44
- const app = createStandaloneRuntime({
45
- packageId: ${JSON.stringify(packageId)},
46
- version: ${JSON.stringify(version)},
47
- description: ${JSON.stringify(description || "")},
48
- config: ${JSON.stringify(configDefs || {})},
49
- actions: [
50
- ${actionArray}
51
- ],
52
- });
53
-
54
- app.run(process.argv.slice(2)).catch((err: unknown) => {
55
- console.error(err);
56
- process.exit(1);
57
- });
58
- `;
59
- }
@@ -1,92 +0,0 @@
1
- import { existsSync, readdirSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { loadManifest } from "../project/manifest";
4
- import type { CatalogSnapshot, IndexedAction } from "./types";
5
-
6
- export class ActionIndex {
7
- private actions = new Map<string, IndexedAction[]>(); // actionId -> IndexedAction[]
8
-
9
- constructor(snapshot: CatalogSnapshot) {
10
- this.indexSnapshot(snapshot);
11
- }
12
-
13
- private indexSnapshot(snapshot: CatalogSnapshot): void {
14
- for (const [packageId, pkg] of snapshot.packages) {
15
- const manifest = loadManifest(pkg.projectRoot);
16
- if (manifest && manifest.actions) {
17
- for (const [actionId, item] of Object.entries(manifest.actions)) {
18
- const indexed: IndexedAction = {
19
- packageId,
20
- actionId,
21
- contract: {
22
- id: actionId,
23
- description: item.description,
24
- inputSchema: item.inputSchema,
25
- outputSchema: item.outputSchema,
26
- uses: item.uses,
27
- tags: item.tags,
28
- annotations: item.annotations as any,
29
- },
30
- entry: item.entry,
31
- projectRoot: pkg.projectRoot,
32
- };
33
- this.add(indexed);
34
- }
35
- } else {
36
- // 向后兼容回退:若未提供清单,扫描 actions 目录生成基础索引
37
- const actionsDir = join(pkg.projectRoot, pkg.config.actionsDir || "actions");
38
- if (existsSync(actionsDir)) {
39
- try {
40
- const files = readdirSync(actionsDir);
41
- for (const file of files) {
42
- if (file.endsWith(".ts") || file.endsWith(".js")) {
43
- const actionId = file.replace(/\.(ts|js)$/, "");
44
- const indexed: IndexedAction = {
45
- packageId,
46
- actionId,
47
- contract: {
48
- id: actionId,
49
- },
50
- entry: join(pkg.config.actionsDir || "actions", file),
51
- projectRoot: pkg.projectRoot,
52
- };
53
- this.add(indexed);
54
- }
55
- }
56
- } catch {
57
- // 忽略读取目录异常
58
- }
59
- }
60
- }
61
- }
62
- }
63
-
64
- private add(action: IndexedAction): void {
65
- let list = this.actions.get(action.actionId);
66
- if (!list) {
67
- list = [];
68
- this.actions.set(action.actionId, list);
69
- }
70
- list.push(action);
71
- }
72
-
73
- public list(packageId?: string): IndexedAction[] {
74
- const all: IndexedAction[] = [];
75
- for (const [_, list] of this.actions) {
76
- for (const action of list) {
77
- if (!packageId || action.packageId === packageId) {
78
- all.push(action);
79
- }
80
- }
81
- }
82
- return all;
83
- }
84
-
85
- public find(actionId: string, packageId?: string): IndexedAction[] {
86
- const matches = this.actions.get(actionId) || [];
87
- if (packageId) {
88
- return matches.filter((a) => a.packageId === packageId);
89
- }
90
- return matches;
91
- }
92
- }
@@ -1,120 +0,0 @@
1
- import type { ActionRef, ResolvedActionRef } from "@actiondock/sdk";
2
- import { ActionIndex } from "./action-index";
3
- import type { CatalogSnapshot, IndexedAction } from "./types";
4
-
5
- export interface ResolveOptions {
6
- currentPackageId?: string;
7
- }
8
-
9
- export class ActionResolver {
10
- private snapshot: CatalogSnapshot;
11
- private index: ActionIndex;
12
-
13
- constructor(snapshot: CatalogSnapshot, index?: ActionIndex) {
14
- this.snapshot = snapshot;
15
- this.index = index || new ActionIndex(snapshot);
16
- }
17
-
18
- /**
19
- * 解析字符串或 ActionRef 为规范化的 ActionRef。
20
- * 支持 greet、my-tools/greet、@team/github/issues.list。
21
- */
22
- public static parseRef(refStringOrObj: string | ActionRef): ActionRef {
23
- if (typeof refStringOrObj === "object") {
24
- return refStringOrObj;
25
- }
26
-
27
- const str = refStringOrObj.trim();
28
- if (str.includes("/")) {
29
- const lastSlashIndex = str.lastIndexOf("/");
30
- const packageId = str.slice(0, lastSlashIndex);
31
- const actionId = str.slice(lastSlashIndex + 1);
32
-
33
- if (actionId.includes(":") || actionId.includes("/") || actionId.includes("..")) {
34
- throw new Error(`Invalid action identifier: '${actionId}'`);
35
- }
36
- return { packageId, actionId };
37
- }
38
-
39
- // 处理旧语法 package:action 的兼容提醒
40
- if (str.includes(":")) {
41
- const parts = str.split(":");
42
- throw new Error(
43
- `Legacy syntax '${str}' is deprecated. Please use '${parts.join("/")}' instead.`
44
- );
45
- }
46
-
47
- return { actionId: str };
48
- }
49
-
50
- public resolve(
51
- refStringOrObj: string | ActionRef,
52
- options: ResolveOptions = {}
53
- ): { resolved: ResolvedActionRef; action: IndexedAction } {
54
- const ref = ActionResolver.parseRef(refStringOrObj);
55
-
56
- // 1. 若指定了 packageId,直接精确匹配
57
- if (ref.packageId) {
58
- const matches = this.index.find(ref.actionId, ref.packageId);
59
- if (matches.length === 0) {
60
- throw new Error(
61
- `ACTION_NOT_FOUND: Action '${ref.actionId}' not found in package '${ref.packageId}'`
62
- );
63
- }
64
- const matched = matches[0];
65
- const pkg = this.snapshot.packages.get(matched.packageId);
66
- return {
67
- resolved: {
68
- packageId: matched.packageId,
69
- packageInstanceId: pkg?.packageInstanceId || matched.packageId,
70
- actionId: matched.actionId,
71
- generationId: this.snapshot.generationId,
72
- },
73
- action: matched,
74
- };
75
- }
76
-
77
- // 2. 未指定 packageId:优先查找当前调用者包
78
- if (options.currentPackageId) {
79
- const inCurrent = this.index.find(ref.actionId, options.currentPackageId);
80
- if (inCurrent.length > 0) {
81
- const matched = inCurrent[0];
82
- const pkg = this.snapshot.packages.get(matched.packageId);
83
- return {
84
- resolved: {
85
- packageId: matched.packageId,
86
- packageInstanceId: pkg?.packageInstanceId || matched.packageId,
87
- actionId: matched.actionId,
88
- generationId: this.snapshot.generationId,
89
- },
90
- action: matched,
91
- };
92
- }
93
- }
94
-
95
- // 3. 全局唯一匹配检查
96
- const allMatches = this.index.find(ref.actionId);
97
- if (allMatches.length === 0) {
98
- throw new Error(`ACTION_NOT_FOUND: Action '${ref.actionId}' not found in any linked package`);
99
- }
100
-
101
- if (allMatches.length > 1) {
102
- const candidates = allMatches.map((m) => `${m.packageId}/${m.actionId}`).join(", ");
103
- throw new Error(
104
- `AMBIGUOUS_ACTION_REF: Action '${ref.actionId}' is provided by multiple packages: ${candidates}. Please specify the package name.`
105
- );
106
- }
107
-
108
- const matched = allMatches[0];
109
- const pkg = this.snapshot.packages.get(matched.packageId);
110
- return {
111
- resolved: {
112
- packageId: matched.packageId,
113
- packageInstanceId: pkg?.packageInstanceId || matched.packageId,
114
- actionId: matched.actionId,
115
- generationId: this.snapshot.generationId,
116
- },
117
- action: matched,
118
- };
119
- }
120
- }
@@ -1,134 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
2
- import { dirname, join, resolve } from "node:path";
3
- import { getActionDockHome } from "../utils";
4
- import type { LocationLink, LocationRegistryData } from "./types";
5
-
6
- export class LocationRegistry {
7
- private filePath: string;
8
-
9
- constructor(customHome?: string) {
10
- const baseDir = getActionDockHome(customHome);
11
- this.filePath = join(baseDir, ".actiondock", "registry.json");
12
- }
13
-
14
- public getFilePath(): string {
15
- return this.filePath;
16
- }
17
-
18
- public load(): LocationRegistryData {
19
- if (!existsSync(this.filePath)) {
20
- return { schemaVersion: 1, links: [] };
21
- }
22
- try {
23
- const raw = readFileSync(this.filePath, "utf-8");
24
- const parsed = JSON.parse(raw);
25
- if (!parsed || typeof parsed !== "object") {
26
- return { schemaVersion: 1, links: [] };
27
- }
28
-
29
- // 处理 2.0 旧格式向 1 迁移
30
- if (parsed.schemaVersion === 1 && Array.isArray(parsed.links)) {
31
- return parsed as LocationRegistryData;
32
- }
33
-
34
- const links: LocationLink[] = [];
35
- if (parsed.workspaces && typeof parsed.workspaces === "object") {
36
- for (const [wsPath, ws] of Object.entries(parsed.workspaces as Record<string, any>)) {
37
- links.push({
38
- type: "workspace",
39
- path: resolve(wsPath),
40
- linkedAt: ws.linkedAt || new Date().toISOString(),
41
- depth: 3,
42
- });
43
- }
44
- }
45
-
46
- if (parsed.packages && typeof parsed.packages === "object") {
47
- for (const [_, pkg] of Object.entries(parsed.packages as Record<string, any>)) {
48
- if (!pkg.workspaceRoot && pkg.path) {
49
- links.push({
50
- type: "package",
51
- path: resolve(pkg.path),
52
- linkedAt: pkg.linkedAt || new Date().toISOString(),
53
- });
54
- }
55
- }
56
- }
57
-
58
- return { schemaVersion: 1, links };
59
- } catch {
60
- return { schemaVersion: 1, links: [] };
61
- }
62
- }
63
-
64
- public save(data: LocationRegistryData): void {
65
- const dir = dirname(this.filePath);
66
- if (!existsSync(dir)) {
67
- mkdirSync(dir, { recursive: true });
68
- }
69
- const tempPath = `${this.filePath}.${process.pid}.${Date.now()}.tmp`;
70
- writeFileSync(tempPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
71
- renameSync(tempPath, this.filePath);
72
- }
73
-
74
- public addLink(path: string, options: { type?: "package" | "workspace"; depth?: number } = {}): LocationLink {
75
- const absPath = resolve(path);
76
- const registry = this.load();
77
- const type = options.type || "package";
78
- const depth = options.depth ?? (type === "workspace" ? 3 : undefined);
79
-
80
- const existingIndex = registry.links.findIndex((l) => l.path === absPath);
81
- const link: LocationLink = {
82
- type,
83
- path: absPath,
84
- linkedAt: new Date().toISOString(),
85
- depth,
86
- };
87
-
88
- if (existingIndex >= 0) {
89
- registry.links[existingIndex] = link;
90
- } else {
91
- registry.links.push(link);
92
- }
93
-
94
- this.save(registry);
95
- return link;
96
- }
97
-
98
- public removeLink(targetPathOrId: string): LocationLink | null {
99
- const registry = this.load();
100
- const absPath = resolve(targetPathOrId);
101
-
102
- const idx = registry.links.findIndex(
103
- (l) => l.path === absPath || l.path.endsWith(`/${targetPathOrId}`)
104
- );
105
-
106
- if (idx >= 0) {
107
- const [removed] = registry.links.splice(idx, 1);
108
- this.save(registry);
109
- return removed;
110
- }
111
- return null;
112
- }
113
-
114
- public prune(): LocationLink[] {
115
- const registry = this.load();
116
- const valid: LocationLink[] = [];
117
- const removed: LocationLink[] = [];
118
-
119
- for (const link of registry.links) {
120
- if (existsSync(link.path)) {
121
- valid.push(link);
122
- } else {
123
- removed.push(link);
124
- }
125
- }
126
-
127
- if (removed.length > 0) {
128
- registry.links = valid;
129
- this.save(registry);
130
- }
131
-
132
- return removed;
133
- }
134
- }
@@ -1,87 +0,0 @@
1
- import { existsSync, realpathSync } from "node:fs";
2
- import { randomUUID } from "node:crypto";
3
- import { resolve } from "node:path";
4
- import { findProjectRoot, loadProjectConfig } from "../project/loader";
5
- import { discoverProjects } from "../registry/registry";
6
- import { LocationRegistry } from "./location-registry";
7
- import type { CatalogPackageEntry, CatalogSnapshot } from "./types";
8
-
9
- export class PackageCatalog {
10
- private registry: LocationRegistry;
11
-
12
- constructor(registry?: LocationRegistry) {
13
- this.registry = registry || new LocationRegistry();
14
- }
15
-
16
- public buildSnapshot(cwd: string = process.cwd()): CatalogSnapshot {
17
- const packages = new Map<string, CatalogPackageEntry>();
18
- const seenRealPaths = new Map<string, string>(); // realPath -> packageId
19
- const seenPackageIds = new Map<string, string>(); // packageId -> realPath
20
-
21
- const registerPackage = (root: string, isChild: boolean = false) => {
22
- const abs = resolve(root);
23
- if (!existsSync(abs)) return;
24
- const real = realpathSync(abs);
25
-
26
- if (seenRealPaths.has(real)) {
27
- return; // 符号链接归一化去重
28
- }
29
-
30
- try {
31
- const config = loadProjectConfig(abs);
32
- if (seenPackageIds.has(config.id)) {
33
- const existingPath = seenPackageIds.get(config.id);
34
- if (existingPath !== real) {
35
- throw new Error(
36
- `PACKAGE_ID_CONFLICT: Package ID '${config.id}' is declared by multiple directories: '${existingPath}' and '${real}'`
37
- );
38
- }
39
- }
40
-
41
- const entry: CatalogPackageEntry = {
42
- id: config.id,
43
- packageInstanceId: `${config.id}:${real}`,
44
- projectRoot: abs,
45
- config,
46
- isWorkspaceChild: isChild,
47
- };
48
-
49
- packages.set(config.id, entry);
50
- seenRealPaths.set(real, config.id);
51
- seenPackageIds.set(config.id, real);
52
- } catch (e: any) {
53
- if (e.message?.startsWith("PACKAGE_ID_CONFLICT")) {
54
- throw e;
55
- }
56
- // 忽略无效项目
57
- }
58
- };
59
-
60
- // 优先包含当前工作目录所在项目
61
- const currentRoot = findProjectRoot(cwd);
62
- if (currentRoot) {
63
- registerPackage(currentRoot);
64
- }
65
-
66
- // 扫描注册表中的位置
67
- const regData = this.registry.load();
68
- for (const link of regData.links) {
69
- if (!existsSync(link.path)) continue;
70
-
71
- if (link.type === "package") {
72
- registerPackage(link.path);
73
- } else if (link.type === "workspace") {
74
- const subprojects = discoverProjects(link.path, link.depth ?? 3);
75
- for (const sub of subprojects) {
76
- registerPackage(sub, true);
77
- }
78
- }
79
- }
80
-
81
- return {
82
- generationId: randomUUID(),
83
- createdAt: new Date().toISOString(),
84
- packages,
85
- };
86
- }
87
- }
@@ -1,75 +0,0 @@
1
- import type { ActionContract, ActionDefinition, ActionRef, ResolvedActionRef } from "@actiondock/sdk";
2
- import type { ProjectConfig } from "../project/types";
3
-
4
- /**
5
- * 注册的位置条目类型。
6
- */
7
- export type LocationType = "package" | "workspace";
8
-
9
- /**
10
- * 位置注册表中的单条链接记录。
11
- */
12
- export interface LocationLink {
13
- /** 位置类型:单包或工作区 */
14
- type: LocationType;
15
- /** 目录绝对物理路径 */
16
- path: string;
17
- /** 注册时间(ISO 8601) */
18
- linkedAt: string;
19
- /** 扫描最大深度(工作区模式有效,默认 3) */
20
- depth?: number;
21
- }
22
-
23
- /**
24
- * 物理位置注册表文件(~/.actiondock/registry.json)格式。
25
- */
26
- export interface LocationRegistryData {
27
- schemaVersion: 1;
28
- links: LocationLink[];
29
- }
30
-
31
- /**
32
- * 解析后的包实例快照。
33
- */
34
- export interface CatalogPackageEntry {
35
- /** 逻辑包标识 */
36
- id: string;
37
- /** 包物理实例唯一标识 */
38
- packageInstanceId: string;
39
- /** 项目根目录绝对路径 */
40
- projectRoot: string;
41
- /** 项目配置 */
42
- config: ProjectConfig;
43
- /** 是否来自工作区自动发现 */
44
- isWorkspaceChild?: boolean;
45
- }
46
-
47
- /**
48
- * 运行时目录与包快照。
49
- */
50
- export interface CatalogSnapshot {
51
- /** 快照代次唯一标识 */
52
- generationId: string;
53
- /** 生成快照时间 */
54
- createdAt: string;
55
- /** 已发现的包集合(按 packageId 索引) */
56
- packages: Map<string, CatalogPackageEntry>;
57
- }
58
-
59
- /**
60
- * 索引中的 Action 描述符。
61
- */
62
- export interface IndexedAction {
63
- /** 所属逻辑包 ID */
64
- packageId: string;
65
- /** 动作 ID */
66
- actionId: string;
67
- /** 契约元数据 */
68
- contract: ActionContract;
69
- /** 实现入口相对路径 */
70
- entry: string;
71
- /** 包根目录绝对路径 */
72
- projectRoot: string;
73
- }
74
-
75
- export type { ModuleLoader } from "../runtime/module-loader";