@shendu-sdt/sdt-dev-agent 0.1.1 → 0.1.3-beta.9

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 (101) hide show
  1. package/README.md +78 -31
  2. package/dist/catalog.d.ts +16 -0
  3. package/dist/catalog.d.ts.map +1 -0
  4. package/dist/catalog.js +98 -0
  5. package/dist/catalog.js.map +1 -0
  6. package/dist/cli/index.js +72 -3
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/commands/add.d.ts +7 -0
  9. package/dist/commands/add.d.ts.map +1 -0
  10. package/dist/commands/add.js +267 -0
  11. package/dist/commands/add.js.map +1 -0
  12. package/dist/commands/init.d.ts.map +1 -1
  13. package/dist/commands/init.js +31 -5
  14. package/dist/commands/init.js.map +1 -1
  15. package/dist/commands/list.d.ts +4 -0
  16. package/dist/commands/list.d.ts.map +1 -0
  17. package/dist/commands/list.js +20 -0
  18. package/dist/commands/list.js.map +1 -0
  19. package/dist/commands/status.d.ts +2 -0
  20. package/dist/commands/status.d.ts.map +1 -0
  21. package/dist/commands/status.js +66 -0
  22. package/dist/commands/status.js.map +1 -0
  23. package/dist/core/capability-discovery.d.ts +23 -0
  24. package/dist/core/capability-discovery.d.ts.map +1 -0
  25. package/dist/core/capability-discovery.js +49 -0
  26. package/dist/core/capability-discovery.js.map +1 -0
  27. package/dist/core/init-options.d.ts +7 -1
  28. package/dist/core/init-options.d.ts.map +1 -1
  29. package/dist/core/init-options.js +64 -34
  30. package/dist/core/init-options.js.map +1 -1
  31. package/dist/core/init-plan.d.ts +25 -1
  32. package/dist/core/init-plan.d.ts.map +1 -1
  33. package/dist/core/init-plan.js +211 -37
  34. package/dist/core/init-plan.js.map +1 -1
  35. package/dist/core/init-writer.d.ts +17 -1
  36. package/dist/core/init-writer.d.ts.map +1 -1
  37. package/dist/core/init-writer.js +72 -19
  38. package/dist/core/init-writer.js.map +1 -1
  39. package/dist/core/manifest.d.ts +8 -0
  40. package/dist/core/manifest.d.ts.map +1 -0
  41. package/dist/core/manifest.js +16 -0
  42. package/dist/core/manifest.js.map +1 -0
  43. package/dist/core/mcp-config.d.ts +12 -0
  44. package/dist/core/mcp-config.d.ts.map +1 -0
  45. package/dist/core/mcp-config.js +60 -0
  46. package/dist/core/mcp-config.js.map +1 -0
  47. package/dist/core/project-inspector.d.ts +1 -0
  48. package/dist/core/project-inspector.d.ts.map +1 -1
  49. package/dist/core/project-inspector.js +4 -0
  50. package/dist/core/project-inspector.js.map +1 -1
  51. package/dist/core/remote-skill-installer.d.ts +16 -0
  52. package/dist/core/remote-skill-installer.d.ts.map +1 -0
  53. package/dist/core/remote-skill-installer.js +104 -0
  54. package/dist/core/remote-skill-installer.js.map +1 -0
  55. package/dist/core/workflow-installer.d.ts +22 -0
  56. package/dist/core/workflow-installer.d.ts.map +1 -0
  57. package/dist/core/workflow-installer.js +103 -0
  58. package/dist/core/workflow-installer.js.map +1 -0
  59. package/dist/types.d.ts +103 -6
  60. package/dist/types.d.ts.map +1 -1
  61. package/dist/types.js +10 -2
  62. package/dist/types.js.map +1 -1
  63. package/dist/utils/follow-up-notice.d.ts +7 -0
  64. package/dist/utils/follow-up-notice.d.ts.map +1 -0
  65. package/dist/utils/follow-up-notice.js +29 -0
  66. package/dist/utils/follow-up-notice.js.map +1 -0
  67. package/dist/utils/init-welcome.d.ts.map +1 -1
  68. package/dist/utils/init-welcome.js +20 -33
  69. package/dist/utils/init-welcome.js.map +1 -1
  70. package/dist/utils/mastergo-notice.d.ts +7 -0
  71. package/dist/utils/mastergo-notice.d.ts.map +1 -0
  72. package/dist/utils/mastergo-notice.js +14 -0
  73. package/dist/utils/mastergo-notice.js.map +1 -0
  74. package/dist/utils/searchable-multi-select.js +5 -6
  75. package/dist/utils/searchable-multi-select.js.map +1 -1
  76. package/dist/utils/styled-select.d.ts.map +1 -1
  77. package/dist/utils/styled-select.js.map +1 -1
  78. package/dist/utils/terminal-theme.d.ts +4 -0
  79. package/dist/utils/terminal-theme.d.ts.map +1 -0
  80. package/dist/utils/terminal-theme.js +25 -0
  81. package/dist/utils/terminal-theme.js.map +1 -0
  82. package/package.json +6 -3
  83. package/templates/bootstrap/project-entry.md +17 -0
  84. package/templates/mcp/context7/claude-code/server.json +6 -0
  85. package/templates/mcp/context7/codex/config.toml +3 -0
  86. package/templates/mcp/mastergo/claude-code/server.json +6 -0
  87. package/templates/mcp/mastergo/codex/config.toml +4 -0
  88. package/templates/skills/builtin/bootstrap-project-docs/SKILL.md +16 -0
  89. package/templates/skills/builtin/bootstrap-project-docs/references/architecture-first.md +7 -0
  90. package/templates/skills/builtin/bootstrap-project-docs/references/tool-rules-follow-up.md +8 -0
  91. package/templates/skills/remote/catalog.json +68 -0
  92. package/templates/workflows/openspec/README.md +7 -0
  93. package/templates/workflows/openspec/claude-code/README.md +7 -0
  94. package/templates/workflows/openspec/codex/README.md +7 -0
  95. package/templates/AGENTS.md +0 -24
  96. package/templates/ARCHITECTURE.md +0 -26
  97. package/templates/capabilities/mcp/README.md +0 -8
  98. package/templates/capabilities/skills/README.md +0 -8
  99. package/templates/docs/ai-collaboration/README.md +0 -16
  100. package/templates/tools/claude-code/README.md +0 -8
  101. package/templates/tools/codex/README.md +0 -8
@@ -1,28 +1,81 @@
1
1
  import path from 'node:path';
2
- import { exists, toPosixPath, writeText } from '../utils/fs.js';
3
- async function collectConflicts(targetPath, plan) {
4
- const conflicts = [];
5
- for (const file of plan.files) {
6
- const absolutePath = path.join(targetPath, file.path);
7
- if (await exists(absolutePath)) {
8
- conflicts.push(file.path);
9
- }
10
- }
11
- return conflicts;
12
- }
13
- export async function applyInitPlan(targetPath, plan) {
14
- const conflicts = await collectConflicts(targetPath, plan);
15
- if (conflicts.length > 0) {
16
- throw new Error(`Initialization aborted. Existing files would be overwritten:\n${conflicts
17
- .map((item) => `- ${item}`)
18
- .join('\n')}`);
19
- }
2
+ import { detectSkillAvailability } from './capability-discovery.js';
3
+ import { mergeMcpConfig, parseConfiguredMcpIds } from './mcp-config.js';
4
+ import { installRemoteSkill } from './remote-skill-installer.js';
5
+ import { exists, readText, toPosixPath, writeText } from '../utils/fs.js';
6
+ /**
7
+ * 执行 `createInitPlan` 产出的计划。
8
+ * 这里负责真实写盘、MCP 合并、远端 skill 安装以及 manifest 最终回写。
9
+ */
10
+ export async function applyInitPlan(targetPath, plan, hooks = {}) {
20
11
  const writtenFiles = [];
12
+ const failedRemoteSkills = [];
21
13
  for (const file of plan.files) {
14
+ if (file.kind === 'manifest') {
15
+ // manifest 需要在远端安装结果落定后再写一次,避免状态不一致。
16
+ continue;
17
+ }
22
18
  const absolutePath = path.join(targetPath, file.path);
19
+ if (file.kind === 'mcp' && (await exists(absolutePath))) {
20
+ const tool = file.path === '.mcp.json' ? 'claude-code' : 'codex';
21
+ const existingContent = await readText(absolutePath);
22
+ const selectedMcps = plan.manifest.mcps
23
+ .filter((mcp) => mcp.installs.some((install) => install.tool === tool && install.path === file.path))
24
+ .map((mcp) => mcp.id);
25
+ const existingServers = parseConfiguredMcpIds(tool, existingContent);
26
+ for (const mcp of plan.manifest.mcps) {
27
+ const installRecord = mcp.installs.find((install) => install.tool === tool && install.path === file.path);
28
+ if (installRecord && existingServers.has(mcp.id)) {
29
+ installRecord.status = 'already-present';
30
+ installRecord.reason = 'already-present';
31
+ }
32
+ }
33
+ const mergedContent = mergeMcpConfig(tool, existingContent, selectedMcps);
34
+ if (mergedContent !== existingContent) {
35
+ await writeText(absolutePath, mergedContent);
36
+ writtenFiles.push(toPosixPath(file.path));
37
+ }
38
+ continue;
39
+ }
23
40
  await writeText(absolutePath, file.content);
24
41
  writtenFiles.push(toPosixPath(file.path));
25
42
  }
26
- return { writtenFiles };
43
+ for (const [index, install] of plan.remoteSkillInstalls.entries()) {
44
+ hooks.onRemoteSkillInstallStart?.(install, index + 1, plan.remoteSkillInstalls.length);
45
+ const availability = await detectSkillAvailability(targetPath, install.tool, install.skillId);
46
+ const skillRecord = plan.manifest.skills.find((skill) => skill.id === install.skillId);
47
+ const installRecord = skillRecord?.installs.find((item) => item.tool === install.tool);
48
+ if (!installRecord) {
49
+ continue;
50
+ }
51
+ if (availability.status === 'already-present') {
52
+ installRecord.status = availability.status;
53
+ installRecord.reason = availability.reason;
54
+ hooks.onRemoteSkillInstallFinish?.(install, 'already-present');
55
+ continue;
56
+ }
57
+ const result = await installRemoteSkill(targetPath, install);
58
+ if (!result.success) {
59
+ installRecord.status = 'failed';
60
+ installRecord.reason = 'install-failed';
61
+ hooks.onRemoteSkillInstallFinish?.(install, 'failed');
62
+ failedRemoteSkills.push({
63
+ skillId: install.skillId,
64
+ tool: install.tool,
65
+ installCommand: install.installCommand,
66
+ error: result.error ?? 'Unknown error',
67
+ });
68
+ continue;
69
+ }
70
+ writtenFiles.push(...result.targetPaths.map((targetPath) => toPosixPath(targetPath)));
71
+ hooks.onRemoteSkillInstallFinish?.(install, 'installed');
72
+ }
73
+ const manifestPath = path.join(targetPath, '.sdt-devagent', 'manifest.json');
74
+ await writeText(manifestPath, `${JSON.stringify(plan.manifest, null, 2)}\n`);
75
+ writtenFiles.push('.sdt-devagent/manifest.json');
76
+ return {
77
+ writtenFiles,
78
+ failedRemoteSkills,
79
+ };
27
80
  }
28
81
  //# sourceMappingURL=init-writer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init-writer.js","sourceRoot":"","sources":["../../src/core/init-writer.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAO/D,KAAK,UAAU,gBAAgB,CAAC,UAAkB,EAAE,IAAc;IAChE,MAAM,SAAS,GAAa,EAAE,CAAA;IAE9B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QACrD,IAAI,MAAM,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB,EAAE,IAAc;IACpE,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;IAC1D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,iEAAiE,SAAS;aACvE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC;aAC1B,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAA;IACH,CAAC;IAED,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QACrD,MAAM,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QAC3C,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3C,CAAC;IAED,OAAO,EAAE,YAAY,EAAE,CAAA;AACzB,CAAC"}
1
+ {"version":3,"file":"init-writer.js","sourceRoot":"","sources":["../../src/core/init-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { InstallManifest } from '../types.js';
2
+ /** `.sdt-devagent/manifest.json` 的固定位置。 */
3
+ export declare function getManifestPath(projectRoot: string): string;
4
+ /** 读取并解析项目内 manifest。 */
5
+ export declare function readInstallManifest(projectRoot: string): Promise<InstallManifest>;
6
+ /** 用格式化 JSON 回写 manifest。 */
7
+ export declare function writeInstallManifest(projectRoot: string, manifest: InstallManifest): Promise<void>;
8
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/core/manifest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,2CAA2C;AAC3C,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,yBAAyB;AACzB,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAGvF;AAED,6BAA6B;AAC7B,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,IAAI,CAAC,CAEf"}
@@ -0,0 +1,16 @@
1
+ import path from 'node:path';
2
+ import { readText, writeText } from '../utils/fs.js';
3
+ /** `.sdt-devagent/manifest.json` 的固定位置。 */
4
+ export function getManifestPath(projectRoot) {
5
+ return path.join(projectRoot, '.sdt-devagent', 'manifest.json');
6
+ }
7
+ /** 读取并解析项目内 manifest。 */
8
+ export async function readInstallManifest(projectRoot) {
9
+ const raw = await readText(getManifestPath(projectRoot));
10
+ return JSON.parse(raw);
11
+ }
12
+ /** 用格式化 JSON 回写 manifest。 */
13
+ export async function writeInstallManifest(projectRoot, manifest) {
14
+ await writeText(getManifestPath(projectRoot), `${JSON.stringify(manifest, null, 2)}\n`);
15
+ }
16
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/core/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAGpD,2CAA2C;AAC3C,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,EAAE,eAAe,CAAC,CAAA;AACjE,CAAC;AAED,yBAAyB;AACzB,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,WAAmB;IAC3D,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAA;IACxD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAA;AAC3C,CAAC;AAED,6BAA6B;AAC7B,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,WAAmB,EACnB,QAAyB;IAEzB,MAAM,SAAS,CAAC,eAAe,CAAC,WAAW,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;AACzF,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { McpId, ToolId } from '../types.js';
2
+ /** 获取某个 MCP 在指定工具下的模板片段。 */
3
+ export declare function getMcpSnippet(tool: ToolId, mcpId: McpId): string;
4
+ /** 组装 Codex 项目的 `config.toml` 片段。 */
5
+ export declare function buildCodexMcpConfig(selectedMcps: McpId[]): string;
6
+ /** 组装 Claude Code 项目的 `.mcp.json` 内容。 */
7
+ export declare function buildClaudeMcpConfig(selectedMcps: McpId[]): string;
8
+ /** 从已有配置中解析出已经声明过的 MCP server ID。 */
9
+ export declare function parseConfiguredMcpIds(tool: ToolId, content: string): Set<string>;
10
+ /** 仅把缺失的 MCP 片段追加进去,已存在的 server 不覆盖。 */
11
+ export declare function mergeMcpConfig(tool: ToolId, existingContent: string, selectedMcps: McpId[]): string;
12
+ //# sourceMappingURL=mcp-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config.d.ts","sourceRoot":"","sources":["../../src/core/mcp-config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAUhD,4BAA4B;AAC5B,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,CAIhE;AAED,qCAAqC;AACrC,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,CAQjE;AAED,yCAAyC;AACzC,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,KAAK,EAAE,GAAG,MAAM,CASlE;AAED,qCAAqC;AACrC,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAShF;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,KAAK,EAAE,GACpB,MAAM,CAsBR"}
@@ -0,0 +1,60 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
5
+ const projectRoot = path.resolve(currentDir, '..', '..');
6
+ /** 从模板目录读取单个 MCP 片段。 */
7
+ function loadTemplate(relativePath) {
8
+ return readFileSync(path.join(projectRoot, 'templates', relativePath), 'utf8');
9
+ }
10
+ /** 获取某个 MCP 在指定工具下的模板片段。 */
11
+ export function getMcpSnippet(tool, mcpId) {
12
+ return tool === 'codex'
13
+ ? loadTemplate(path.join('mcp', mcpId, 'codex', 'config.toml'))
14
+ : loadTemplate(path.join('mcp', mcpId, 'claude-code', 'server.json'));
15
+ }
16
+ /** 组装 Codex 项目的 `config.toml` 片段。 */
17
+ export function buildCodexMcpConfig(selectedMcps) {
18
+ const lines = ['# Managed by SDT DevAgent'];
19
+ for (const mcpId of selectedMcps) {
20
+ lines.push('', getMcpSnippet('codex', mcpId).trimEnd());
21
+ }
22
+ return `${lines.join('\n')}\n`;
23
+ }
24
+ /** 组装 Claude Code 项目的 `.mcp.json` 内容。 */
25
+ export function buildClaudeMcpConfig(selectedMcps) {
26
+ const mcpServers = {};
27
+ for (const mcpId of selectedMcps) {
28
+ const parsed = JSON.parse(getMcpSnippet('claude-code', mcpId));
29
+ Object.assign(mcpServers, parsed);
30
+ }
31
+ return `${JSON.stringify({ mcpServers }, null, 2)}\n`;
32
+ }
33
+ /** 从已有配置中解析出已经声明过的 MCP server ID。 */
34
+ export function parseConfiguredMcpIds(tool, content) {
35
+ if (tool === 'codex') {
36
+ return new Set([...content.matchAll(/^\[mcp_servers\.([A-Za-z0-9_-]+)\]$/gm)].map((match) => match[1]));
37
+ }
38
+ const parsed = JSON.parse(content);
39
+ return new Set(Object.keys(parsed.mcpServers ?? {}));
40
+ }
41
+ /** 仅把缺失的 MCP 片段追加进去,已存在的 server 不覆盖。 */
42
+ export function mergeMcpConfig(tool, existingContent, selectedMcps) {
43
+ const existingServers = parseConfiguredMcpIds(tool, existingContent);
44
+ const missingMcps = selectedMcps.filter((mcpId) => !existingServers.has(mcpId));
45
+ if (missingMcps.length === 0) {
46
+ return existingContent.endsWith('\n') ? existingContent : `${existingContent}\n`;
47
+ }
48
+ if (tool === 'codex') {
49
+ const additions = missingMcps.map((mcpId) => getMcpSnippet(tool, mcpId).trim());
50
+ const base = existingContent.trimEnd();
51
+ return `${base}\n\n${additions.join('\n\n')}\n`;
52
+ }
53
+ const parsed = JSON.parse(existingContent);
54
+ const mergedServers = { ...(parsed.mcpServers ?? {}) };
55
+ for (const mcpId of missingMcps) {
56
+ Object.assign(mergedServers, JSON.parse(getMcpSnippet(tool, mcpId)));
57
+ }
58
+ return `${JSON.stringify({ ...parsed, mcpServers: mergedServers }, null, 2)}\n`;
59
+ }
60
+ //# sourceMappingURL=mcp-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config.js","sourceRoot":"","sources":["../../src/core/mcp-config.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  import type { ProjectFacts } from '../types.js';
2
+ /** `init` 当前只关注最小项目事实,不做框架和业务层深入探测。 */
2
3
  export declare function inspectProject(targetPath: string): Promise<ProjectFacts>;
3
4
  //# sourceMappingURL=project-inspector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-inspector.d.ts","sourceRoot":"","sources":["../../src/core/project-inspector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAkD/C,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAa9E"}
1
+ {"version":3,"file":"project-inspector.d.ts","sourceRoot":"","sources":["../../src/core/project-inspector.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAqD/C,uCAAuC;AACvC,wBAAsB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAa9E"}
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { exists, readText } from '../utils/fs.js';
3
+ /** 通过常见 lockfile 推断项目包管理器。 */
3
4
  async function detectPackageManager(targetPath) {
4
5
  const checks = [
5
6
  ['pnpm-lock.yaml', 'pnpm'],
@@ -14,6 +15,7 @@ async function detectPackageManager(targetPath) {
14
15
  }
15
16
  return 'unknown';
16
17
  }
18
+ /** 读取项目名;没有 `package.json` 时回退到目录名。 */
17
19
  async function detectProjectName(targetPath) {
18
20
  const packageJsonPath = path.join(targetPath, 'package.json');
19
21
  if (!(await exists(packageJsonPath))) {
@@ -29,6 +31,7 @@ async function detectProjectName(targetPath) {
29
31
  hasPackageJson: true,
30
32
  };
31
33
  }
34
+ /** 在一组候选目录里找第一个存在的目录作为事实值。 */
32
35
  async function detectDirectory(targetPath, candidates) {
33
36
  for (const candidate of candidates) {
34
37
  if (await exists(path.join(targetPath, candidate))) {
@@ -37,6 +40,7 @@ async function detectDirectory(targetPath, candidates) {
37
40
  }
38
41
  return 'N/A';
39
42
  }
43
+ /** `init` 当前只关注最小项目事实,不做框架和业务层深入探测。 */
40
44
  export async function inspectProject(targetPath) {
41
45
  const project = await detectProjectName(targetPath);
42
46
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"project-inspector.js","sourceRoot":"","sources":["../../src/core/project-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAGjD,KAAK,UAAU,oBAAoB,CAAC,UAAkB;IACpD,MAAM,MAAM,GAA4B;QACtC,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAC1B,CAAC,mBAAmB,EAAE,KAAK,CAAC;QAC5B,CAAC,WAAW,EAAE,MAAM,CAAC;QACrB,CAAC,WAAW,EAAE,KAAK,CAAC;KACrB,CAAA;IAED,KAAK,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,IAAI,MAAM,EAAE,CAAC;QAChD,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YAClD,OAAO,cAAc,CAAA;QACvB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,UAAkB;IAIjD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IAC7D,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC;QACrC,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;YACtC,cAAc,EAAE,KAAK;SACtB,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,CAAA;IAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAA;IAExD,OAAO;QACL,WAAW,EAAE,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC1D,cAAc,EAAE,IAAI;KACrB,CAAA;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,UAAkB,EAAE,UAAoB;IACrE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;YACnD,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAkB;IACrD,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAEnD,OAAO;QACL,UAAU;QACV,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,cAAc,EAAE,MAAM,oBAAoB,CAAC,UAAU,CAAC;QACtD,UAAU,EAAE,MAAM,eAAe,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QACzE,QAAQ,EAAE,MAAM,eAAe,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QAC3E,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,SAAS,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC3D,UAAU,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;KACxD,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"project-inspector.js","sourceRoot":"","sources":["../../src/core/project-inspector.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAGjD,8BAA8B;AAC9B,KAAK,UAAU,oBAAoB,CAAC,UAAkB;IACpD,MAAM,MAAM,GAA4B;QACtC,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAC1B,CAAC,mBAAmB,EAAE,KAAK,CAAC;QAC5B,CAAC,WAAW,EAAE,MAAM,CAAC;QACrB,CAAC,WAAW,EAAE,KAAK,CAAC;KACrB,CAAA;IAED,KAAK,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,IAAI,MAAM,EAAE,CAAC;QAChD,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;YAClD,OAAO,cAAc,CAAA;QACvB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,uCAAuC;AACvC,KAAK,UAAU,iBAAiB,CAAC,UAAkB;IAIjD,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAA;IAC7D,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,EAAE,CAAC;QACrC,OAAO;YACL,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;YACtC,cAAc,EAAE,KAAK;SACtB,CAAA;IACH,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,CAAA;IAC3C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAsB,CAAA;IAExD,OAAO;QACL,WAAW,EAAE,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;QAC1D,cAAc,EAAE,IAAI;KACrB,CAAA;AACH,CAAC;AAED,8BAA8B;AAC9B,KAAK,UAAU,eAAe,CAAC,UAAkB,EAAE,UAAoB;IACrE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC;YACnD,OAAO,SAAS,CAAA;QAClB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAED,uCAAuC;AACvC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,UAAkB;IACrD,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,UAAU,CAAC,CAAA;IAEnD,OAAO;QACL,UAAU;QACV,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,cAAc,EAAE,MAAM,oBAAoB,CAAC,UAAU,CAAC;QACtD,UAAU,EAAE,MAAM,eAAe,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;QACzE,QAAQ,EAAE,MAAM,eAAe,CAAC,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;QAC3E,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,SAAS,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC3D,UAAU,EAAE,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;KACxD,CAAA;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { PlannedRemoteSkillInstall } from '../types.js';
2
+ /** 单次远端 skill 安装后的结果摘要。 */
3
+ export interface RemoteSkillInstallResult {
4
+ tool: PlannedRemoteSkillInstall['tool'];
5
+ skillId: PlannedRemoteSkillInstall['skillId'];
6
+ targetPaths: string[];
7
+ installCommand: string;
8
+ success: boolean;
9
+ error?: string;
10
+ }
11
+ /**
12
+ * 执行远端 skill 安装。
13
+ * 成功标准不是退出码,而是安装后项目级目标路径已经真实出现。
14
+ */
15
+ export declare function installRemoteSkill(projectRoot: string, install: PlannedRemoteSkillInstall): Promise<RemoteSkillInstallResult>;
16
+ //# sourceMappingURL=remote-skill-installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-skill-installer.d.ts","sourceRoot":"","sources":["../../src/core/remote-skill-installer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAE5D,2BAA2B;AAC3B,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,yBAAyB,CAAC,MAAM,CAAC,CAAA;IACvC,OAAO,EAAE,yBAAyB,CAAC,SAAS,CAAC,CAAA;IAC7C,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAoDD;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,wBAAwB,CAAC,CAwEnC"}
@@ -0,0 +1,104 @@
1
+ import { spawn } from 'node:child_process';
2
+ import path from 'node:path';
3
+ import { hasProjectSkillInstall } from './capability-discovery.js';
4
+ /** 最小的子进程执行包装;统一收集 stdout/stderr 作为错误上下文。 */
5
+ function runCommand(command, args, env, cwd) {
6
+ return new Promise((resolve) => {
7
+ const child = spawn(command, args, {
8
+ cwd,
9
+ env,
10
+ stdio: ['ignore', 'pipe', 'pipe'],
11
+ shell: process.platform === 'win32',
12
+ });
13
+ let stdout = '';
14
+ let stderr = '';
15
+ child.stdout?.setEncoding('utf8');
16
+ child.stderr?.setEncoding('utf8');
17
+ child.stdout?.on('data', (chunk) => {
18
+ stdout += chunk;
19
+ });
20
+ child.stderr?.on('data', (chunk) => {
21
+ stderr += chunk;
22
+ });
23
+ child.on('error', (error) => {
24
+ resolve({
25
+ success: false,
26
+ error: error.message,
27
+ });
28
+ });
29
+ child.on('close', (code, signal) => {
30
+ const output = [stdout.trim(), stderr.trim()].filter(Boolean).join('\n');
31
+ if (code === 0) {
32
+ resolve({ success: true, output });
33
+ return;
34
+ }
35
+ resolve({
36
+ success: false,
37
+ error: output || `Command failed with ${signal ? `signal ${signal}` : `exit code ${code}`}`,
38
+ });
39
+ });
40
+ });
41
+ }
42
+ /**
43
+ * 执行远端 skill 安装。
44
+ * 成功标准不是退出码,而是安装后项目级目标路径已经真实出现。
45
+ */
46
+ export async function installRemoteSkill(projectRoot, install) {
47
+ const stubPath = process.env.SDT_DEV_AGENT_SKILLS_STUB_PATH;
48
+ const targetPaths = install.installTargets.map((target) => target.targetPath);
49
+ let execution;
50
+ if (stubPath) {
51
+ // 测试环境通过 stub 精确控制安装结果,避免真实依赖网络和外部 CLI。
52
+ for (const target of install.installTargets) {
53
+ execution = await runCommand(process.execPath, [stubPath, target.skillName, install.tool, path.join(projectRoot, target.targetPath)], process.env, projectRoot);
54
+ if (!execution.success) {
55
+ return {
56
+ tool: install.tool,
57
+ skillId: install.skillId,
58
+ targetPaths,
59
+ installCommand: install.installCommand,
60
+ success: false,
61
+ error: execution.error,
62
+ };
63
+ }
64
+ }
65
+ execution = { success: true, output: '' };
66
+ }
67
+ else {
68
+ // 正常链路复用 skills CLI,把能力直接 copy 到项目级目录。
69
+ const skillNames = install.installTargets.map((target) => target.skillName);
70
+ execution = await runCommand('npx', [
71
+ '-y',
72
+ 'skills',
73
+ 'add',
74
+ install.source,
75
+ '--yes',
76
+ '--skill',
77
+ ...skillNames,
78
+ '--copy',
79
+ '-a',
80
+ install.tool,
81
+ ], process.env, projectRoot);
82
+ }
83
+ if (execution.success && !hasProjectSkillInstall(projectRoot, install.tool, install.skillId)) {
84
+ const expectedPaths = targetPaths.join(', ');
85
+ const detail = execution.output ? `\nCommand output:\n${execution.output}` : '';
86
+ return {
87
+ tool: install.tool,
88
+ skillId: install.skillId,
89
+ targetPaths,
90
+ installCommand: install.installCommand,
91
+ success: false,
92
+ error: `Command exited successfully but the expected project skill paths were not written: ${expectedPaths}.${detail}`,
93
+ };
94
+ }
95
+ return {
96
+ tool: install.tool,
97
+ skillId: install.skillId,
98
+ targetPaths,
99
+ installCommand: install.installCommand,
100
+ success: execution.success,
101
+ error: execution.success ? undefined : execution.error,
102
+ };
103
+ }
104
+ //# sourceMappingURL=remote-skill-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-skill-installer.js","sourceRoot":"","sources":["../../src/core/remote-skill-installer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { ToolId, WorkflowId } from '../types.js';
2
+ /** `add workflow` 传给安装器的最小输入。 */
3
+ export interface PlannedWorkflowInstall {
4
+ tool: ToolId;
5
+ workflowId: WorkflowId;
6
+ installCommand: string;
7
+ }
8
+ /** 单次 workflow 安装后的结果摘要。 */
9
+ export interface WorkflowInstallResult {
10
+ tool: ToolId;
11
+ workflowId: WorkflowId;
12
+ targetPaths: string[];
13
+ installCommand: string;
14
+ success: boolean;
15
+ error?: string;
16
+ }
17
+ /**
18
+ * 执行 workflow 安装。
19
+ * 当前策略是优先走本机命令,失败时再回退到官方 `npx` 入口。
20
+ */
21
+ export declare function installWorkflow(projectRoot: string, install: PlannedWorkflowInstall): Promise<WorkflowInstallResult>;
22
+ //# sourceMappingURL=workflow-installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-installer.d.ts","sourceRoot":"","sources":["../../src/core/workflow-installer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAErD,iCAAiC;AACjC,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,UAAU,CAAA;IACtB,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,4BAA4B;AAC5B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,UAAU,CAAA;IACtB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAyDD;;;GAGG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,qBAAqB,CAAC,CAyEhC"}
@@ -0,0 +1,103 @@
1
+ import { spawn } from 'node:child_process';
2
+ import path from 'node:path';
3
+ import { hasProjectWorkflowInstall } from './capability-discovery.js';
4
+ import { getWorkflowTargetPaths } from './init-plan.js';
5
+ /** 最小的子进程执行包装;统一收集 stdout/stderr 作为错误上下文。 */
6
+ function runCommand(command, args, env, cwd) {
7
+ return new Promise((resolve) => {
8
+ const child = spawn(command, args, {
9
+ cwd,
10
+ env,
11
+ stdio: ['ignore', 'pipe', 'pipe'],
12
+ shell: process.platform === 'win32',
13
+ });
14
+ let stdout = '';
15
+ let stderr = '';
16
+ child.stdout?.setEncoding('utf8');
17
+ child.stderr?.setEncoding('utf8');
18
+ child.stdout?.on('data', (chunk) => {
19
+ stdout += chunk;
20
+ });
21
+ child.stderr?.on('data', (chunk) => {
22
+ stderr += chunk;
23
+ });
24
+ child.on('error', (error) => {
25
+ resolve({
26
+ success: false,
27
+ error: error.message,
28
+ });
29
+ });
30
+ child.on('close', (code, signal) => {
31
+ const output = [stdout.trim(), stderr.trim()].filter(Boolean).join('\n');
32
+ if (code === 0) {
33
+ resolve({ success: true, output });
34
+ return;
35
+ }
36
+ resolve({
37
+ success: false,
38
+ error: output || `Command failed with ${signal ? `signal ${signal}` : `exit code ${code}`}`,
39
+ });
40
+ });
41
+ });
42
+ }
43
+ /** `OpenSpec` CLI 使用的工具名与本仓库内部枚举不同。 */
44
+ function mapOpenSpecToolId(tool) {
45
+ return tool === 'claude-code' ? 'claude' : 'codex';
46
+ }
47
+ /**
48
+ * 执行 workflow 安装。
49
+ * 当前策略是优先走本机命令,失败时再回退到官方 `npx` 入口。
50
+ */
51
+ export async function installWorkflow(projectRoot, install) {
52
+ const stubPath = process.env.SDT_DEV_AGENT_WORKFLOWS_STUB_PATH;
53
+ const targetPaths = getWorkflowTargetPaths(install.tool, install.workflowId);
54
+ let execution;
55
+ if (stubPath) {
56
+ // 测试环境直接走 stub,避免依赖真实 OpenSpec CLI。
57
+ execution = await runCommand(process.execPath, [
58
+ stubPath,
59
+ install.workflowId,
60
+ install.tool,
61
+ ...targetPaths.map((targetPath) => path.join(projectRoot, targetPath)),
62
+ ], process.env, projectRoot);
63
+ }
64
+ else {
65
+ // 优先复用用户本机已安装的 openspec,失败时再回退到 npx。
66
+ const toolArg = mapOpenSpecToolId(install.tool);
67
+ execution = await runCommand('openspec', ['init', '--tools', toolArg, '--profile', 'core', projectRoot], process.env, projectRoot);
68
+ if (!execution.success) {
69
+ execution = await runCommand('npx', [
70
+ '-y',
71
+ '@fission-ai/openspec@latest',
72
+ 'init',
73
+ '--tools',
74
+ toolArg,
75
+ '--profile',
76
+ 'core',
77
+ projectRoot,
78
+ ], process.env, projectRoot);
79
+ }
80
+ }
81
+ if (execution.success &&
82
+ !hasProjectWorkflowInstall(projectRoot, install.tool, install.workflowId)) {
83
+ const expectedPaths = targetPaths.join(', ');
84
+ const detail = 'output' in execution && execution.output ? `\nCommand output:\n${execution.output}` : '';
85
+ return {
86
+ tool: install.tool,
87
+ workflowId: install.workflowId,
88
+ targetPaths,
89
+ installCommand: install.installCommand,
90
+ success: false,
91
+ error: `Command exited successfully but the expected project workflow paths were not written: ${expectedPaths}.${detail}`,
92
+ };
93
+ }
94
+ return {
95
+ tool: install.tool,
96
+ workflowId: install.workflowId,
97
+ targetPaths,
98
+ installCommand: install.installCommand,
99
+ success: execution.success,
100
+ error: execution.success ? undefined : execution.error,
101
+ };
102
+ }
103
+ //# sourceMappingURL=workflow-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-installer.js","sourceRoot":"","sources":["../../src/core/workflow-installer.ts"],"names":[],"mappings":"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"}