@open-agent-toolkit/cli 0.2.13 → 0.2.15

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 (79) hide show
  1. package/assets/agents/oat-phase-implementer.md +5 -2
  2. package/assets/agents/oat-reviewer.md +2 -2
  3. package/assets/docs/cli-utilities/config-and-local-state.md +14 -1
  4. package/assets/docs/cli-utilities/configuration.md +23 -2
  5. package/assets/docs/cli-utilities/tool-packs.md +68 -24
  6. package/assets/docs/contributing/skills.md +17 -10
  7. package/assets/docs/provider-sync/providers.md +26 -0
  8. package/assets/docs/reference/cli-reference.md +1 -1
  9. package/assets/docs/reference/troubleshooting.md +42 -0
  10. package/assets/docs/workflows/projects/lifecycle.md +2 -2
  11. package/assets/docs/workflows/projects/orchestration-model.md +14 -7
  12. package/assets/docs/workflows/projects/programmatic-execution.md +1 -1
  13. package/assets/docs/workflows/projects/reviews.md +18 -11
  14. package/assets/docs/workflows/skills/index.md +2 -0
  15. package/assets/docs/workflows/skills/repo-improve.md +13 -1
  16. package/assets/public-package-versions.json +4 -4
  17. package/assets/skills/oat-agent-instructions-analyze/SKILL.md +2 -2
  18. package/assets/skills/oat-brainstorm/SKILL.md +8 -8
  19. package/assets/skills/oat-brainstorm/references/destinations.md +3 -3
  20. package/assets/skills/oat-cursor-cloud-projects/SKILL.md +12 -5
  21. package/assets/skills/oat-dispatch-subagents/SKILL.md +81 -24
  22. package/assets/skills/oat-dispatch-subagents/references/provider-claude.md +10 -7
  23. package/assets/skills/oat-dispatch-subagents/references/provider-codex.md +18 -13
  24. package/assets/skills/oat-dispatch-subagents/references/provider-cursor.md +30 -23
  25. package/assets/skills/oat-dispatch-subagents/references/record-schema.md +86 -2
  26. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +4 -4
  27. package/assets/skills/oat-project-dispatch-subagents/SKILL.md +8 -3
  28. package/assets/skills/oat-project-document/SKILL.md +4 -4
  29. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +4 -4
  30. package/assets/skills/oat-project-implement/SKILL.md +9 -5
  31. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +4 -4
  32. package/assets/skills/oat-project-plan-writing/SKILL.md +9 -5
  33. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +4 -4
  34. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +4 -4
  35. package/assets/skills/oat-project-summary/SKILL.md +9 -9
  36. package/assets/skills/oat-repo-improve/SKILL.md +9 -2
  37. package/assets/skills/subagent-orchestration/SKILL.md +109 -0
  38. package/assets/skills/subagent-orchestration/references/evidence-and-refresh.md +103 -0
  39. package/assets/skills/subagent-orchestration/references/model-selection-principles.md +105 -0
  40. package/assets/skills/subagent-orchestration/references/provider-claude.md +81 -0
  41. package/assets/skills/subagent-orchestration/references/provider-codex.md +63 -0
  42. package/assets/skills/subagent-orchestration/references/provider-cursor.md +78 -0
  43. package/dist/commands/init/tools/brainstorm/index.d.ts +0 -3
  44. package/dist/commands/init/tools/brainstorm/index.d.ts.map +1 -1
  45. package/dist/commands/init/tools/brainstorm/index.js +0 -12
  46. package/dist/commands/init/tools/index.d.ts.map +1 -1
  47. package/dist/commands/init/tools/index.js +46 -25
  48. package/dist/commands/init/tools/shared/skill-manifest.d.ts +1 -1
  49. package/dist/commands/init/tools/shared/skill-manifest.d.ts.map +1 -1
  50. package/dist/commands/init/tools/shared/skill-manifest.js +1 -0
  51. package/dist/commands/init/tools/utility/index.d.ts.map +1 -1
  52. package/dist/commands/init/tools/utility/index.js +16 -2
  53. package/dist/commands/tools/has/has-pack.d.ts +18 -0
  54. package/dist/commands/tools/has/has-pack.d.ts.map +1 -0
  55. package/dist/commands/tools/has/has-pack.js +33 -0
  56. package/dist/commands/tools/has/index.d.ts +4 -0
  57. package/dist/commands/tools/has/index.d.ts.map +1 -0
  58. package/dist/commands/tools/has/index.js +57 -0
  59. package/dist/commands/tools/index.d.ts.map +1 -1
  60. package/dist/commands/tools/index.js +2 -0
  61. package/dist/commands/tools/remove/index.d.ts.map +1 -1
  62. package/dist/commands/tools/remove/index.js +10 -20
  63. package/dist/commands/tools/shared/project-tools-config.d.ts +16 -0
  64. package/dist/commands/tools/shared/project-tools-config.d.ts.map +1 -0
  65. package/dist/commands/tools/shared/project-tools-config.js +59 -0
  66. package/dist/commands/tools/update/index.d.ts.map +1 -1
  67. package/dist/commands/tools/update/index.js +11 -22
  68. package/dist/engine/compute-plan.d.ts.map +1 -1
  69. package/dist/engine/compute-plan.js +8 -2
  70. package/dist/engine/execute-plan.d.ts +5 -1
  71. package/dist/engine/execute-plan.d.ts.map +1 -1
  72. package/dist/engine/execute-plan.js +23 -1
  73. package/dist/engine/index.d.ts +1 -0
  74. package/dist/engine/index.d.ts.map +1 -1
  75. package/dist/engine/index.js +1 -0
  76. package/dist/engine/provider-path-safety.d.ts +2 -0
  77. package/dist/engine/provider-path-safety.d.ts.map +1 -0
  78. package/dist/engine/provider-path-safety.js +54 -0
  79. package/package.json +2 -2
@@ -0,0 +1,33 @@
1
+ export const PACK_NAMES = [
2
+ 'core',
3
+ 'ideas',
4
+ 'docs',
5
+ 'workflows',
6
+ 'utility',
7
+ 'project-management',
8
+ 'research',
9
+ 'brainstorm',
10
+ ];
11
+ export function isPackName(value) {
12
+ return PACK_NAMES.includes(value);
13
+ }
14
+ export async function resolvePackAvailability(pack, scopes, context, dependencies) {
15
+ const assetsRoot = await dependencies.resolveAssetsRoot();
16
+ const matchingScopes = [];
17
+ for (const scope of scopes) {
18
+ const scopeRoot = await dependencies.resolveScopeRoot(scope, context.cwd, context.home);
19
+ const tools = await dependencies.scanTools({
20
+ scope,
21
+ scopeRoot,
22
+ assetsRoot,
23
+ });
24
+ if (tools.some((tool) => tool.pack === pack)) {
25
+ matchingScopes.push(scope);
26
+ }
27
+ }
28
+ return {
29
+ pack,
30
+ available: matchingScopes.length > 0,
31
+ scopes: matchingScopes,
32
+ };
33
+ }
@@ -0,0 +1,4 @@
1
+ import { Command } from 'commander';
2
+ import { type PackAvailabilityDependencies } from './has-pack.js';
3
+ export declare function createToolsHasCommand(dependencies?: PackAvailabilityDependencies): Command;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/has/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,KAAK,4BAA4B,EAIlC,MAAM,YAAY,CAAC;AAapB,wBAAgB,qBAAqB,CACnC,YAAY,GAAE,4BAAkD,GAC/D,OAAO,CA0CT"}
@@ -0,0 +1,57 @@
1
+ import { buildCommandContext } from '../../../app/command-context.js';
2
+ import { withScopeOption } from '../../shared/scope-option.js';
3
+ import { readGlobalOptions, resolveConcreteScopes, } from '../../shared/shared.utils.js';
4
+ import { scanTools } from '../../tools/shared/scan-tools.js';
5
+ import { resolveAssetsRoot } from '../../../fs/assets.js';
6
+ import { resolveProjectRoot, resolveScopeRoot } from '../../../fs/paths.js';
7
+ import { Command } from 'commander';
8
+ import { PACK_NAMES, isPackName, resolvePackAvailability, } from './has-pack.js';
9
+ const defaultDependencies = {
10
+ scanTools,
11
+ resolveScopeRoot: async (scope, cwd, home) => {
12
+ if (scope === 'project') {
13
+ return resolveProjectRoot(cwd);
14
+ }
15
+ return resolveScopeRoot(scope, cwd, home);
16
+ },
17
+ resolveAssetsRoot,
18
+ };
19
+ export function createToolsHasCommand(dependencies = defaultDependencies) {
20
+ return withScopeOption(new Command('has'))
21
+ .description('Check whether a bundled tool pack is available')
22
+ .argument('<pack>', 'Bundled tool pack name')
23
+ .action(async (pack, _options, command) => {
24
+ const context = buildCommandContext(readGlobalOptions(command));
25
+ if (!isPackName(pack)) {
26
+ const message = `Invalid pack '${pack}'. Expected one of: ${PACK_NAMES.join(', ')}.`;
27
+ if (context.json) {
28
+ context.logger.json({ status: 'error', message });
29
+ }
30
+ else {
31
+ context.logger.error(message);
32
+ }
33
+ process.exitCode = 1;
34
+ return;
35
+ }
36
+ try {
37
+ const availability = await resolvePackAvailability(pack, resolveConcreteScopes(context.scope), context, dependencies);
38
+ if (context.json) {
39
+ context.logger.json(availability);
40
+ }
41
+ else {
42
+ context.logger.info(String(availability.available));
43
+ }
44
+ process.exitCode = 0;
45
+ }
46
+ catch (error) {
47
+ const message = error instanceof Error ? error.message : String(error);
48
+ if (context.json) {
49
+ context.logger.json({ status: 'error', message });
50
+ }
51
+ else {
52
+ context.logger.error(message);
53
+ }
54
+ process.exitCode = 2;
55
+ }
56
+ });
57
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,kBAAkB,IAAI,OAAO,CAa5C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,wBAAgB,kBAAkB,IAAI,OAAO,CAc5C"}
@@ -1,4 +1,5 @@
1
1
  import { Command } from 'commander';
2
+ import { createToolsHasCommand } from './has/index.js';
2
3
  import { createToolsInfoCommand } from './info/index.js';
3
4
  import { createToolsInstallCommand } from './install/index.js';
4
5
  import { createToolsListCommand } from './list/index.js';
@@ -10,6 +11,7 @@ export function createToolsCommand() {
10
11
  cmd.addCommand(createToolsListCommand());
11
12
  cmd.addCommand(createToolsOutdatedCommand());
12
13
  cmd.addCommand(createToolsInfoCommand());
14
+ cmd.addCommand(createToolsHasCommand());
13
15
  cmd.addCommand(createToolsUpdateCommand());
14
16
  cmd.addCommand(createToolsRemoveCommand());
15
17
  cmd.addCommand(createToolsInstallCommand());
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/remove/index.ts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,kCAAkC,CAAC;AAM1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,uBAAuB,EAE7B,MAAM,gBAAgB,CAAC;AA4CxB,wBAAgB,wBAAwB,CACtC,YAAY,GAAE,uBAA6C,EAC3D,gBAAgB,GAAE,oBAA8C,GAC/D,OAAO,CAwGT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/remove/index.ts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,kCAAkC,CAAC;AAO1C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAEL,KAAK,uBAAuB,EAE7B,MAAM,gBAAgB,CAAC;AA4CxB,wBAAgB,wBAAwB,CACtC,YAAY,GAAE,uBAA6C,EAC3D,gBAAgB,GAAE,oBAA8C,GAC/D,OAAO,CAuFT"}
@@ -4,6 +4,7 @@ import { buildCommandContext } from '../../../app/command-context.js';
4
4
  import { withScopeOption } from '../../shared/scope-option.js';
5
5
  import { readGlobalOptions, resolveConcreteScopes, } from '../../shared/shared.utils.js';
6
6
  import { autoSync, } from '../../tools/shared/auto-sync.js';
7
+ import { reconcileProjectToolsConfig } from '../../tools/shared/project-tools-config.js';
7
8
  import { scanTools } from '../../tools/shared/scan-tools.js';
8
9
  import { readOatConfig, writeOatConfig } from '../../../config/oat-config.js';
9
10
  import { resolveAssetsRoot } from '../../../fs/assets.js';
@@ -69,27 +70,16 @@ export function createToolsRemoveCommand(dependencies = defaultDependencies, syn
69
70
  const dryRun = opts.dryRun ?? false;
70
71
  const result = await removeTools(target, scopes, context.cwd, context.home, dryRun, dependencies);
71
72
  if (!dryRun && result.removed.length > 0) {
72
- const assetsRoot = await dependencies.resolveAssetsRoot();
73
73
  const repoRoot = await resolveProjectRoot(context.cwd);
74
- const config = await readOatConfig(repoRoot);
75
- const installedPacks = new Set();
76
- const configScopes = resolveConcreteScopes('all');
77
- for (const scope of configScopes) {
78
- const scopeRoot = await dependencies.resolveScopeRoot(scope, context.cwd, context.home);
79
- const tools = await dependencies.scanTools({
80
- scope,
81
- scopeRoot,
82
- assetsRoot,
83
- });
84
- for (const tool of tools) {
85
- if (tool.pack !== 'custom') {
86
- installedPacks.add(tool.pack);
87
- }
88
- }
89
- }
90
- await writeOatConfig(repoRoot, {
91
- ...config,
92
- tools: Object.fromEntries(VALID_PACKS.map((pack) => [pack, installedPacks.has(pack)])),
74
+ await reconcileProjectToolsConfig({
75
+ repoRoot,
76
+ cwd: context.cwd,
77
+ home: context.home,
78
+ }, {
79
+ resolveAssetsRoot: dependencies.resolveAssetsRoot,
80
+ scanTools: dependencies.scanTools,
81
+ readOatConfig,
82
+ writeOatConfig,
93
83
  });
94
84
  }
95
85
  if (result.notInstalled.length > 0) {
@@ -0,0 +1,16 @@
1
+ import { type OatConfig } from '../../../config/oat-config.js';
2
+ import { type ScanToolsOptions } from './scan-tools.js';
3
+ import type { ToolInfo } from './types.js';
4
+ export interface ReconcileProjectToolsOptions {
5
+ repoRoot: string;
6
+ cwd: string;
7
+ home: string;
8
+ }
9
+ export interface ProjectToolsConfigDependencies {
10
+ resolveAssetsRoot: () => Promise<string>;
11
+ scanTools: (options: ScanToolsOptions) => Promise<ToolInfo[]>;
12
+ readOatConfig: (repoRoot: string) => Promise<OatConfig>;
13
+ writeOatConfig: (repoRoot: string, config: OatConfig) => Promise<void>;
14
+ }
15
+ export declare function reconcileProjectToolsConfig(options: ReconcileProjectToolsOptions, dependencies?: ProjectToolsConfigDependencies): Promise<'written' | 'unchanged'>;
16
+ //# sourceMappingURL=project-tools-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-tools-config.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/shared/project-tools-config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAa,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,SAAS,CAAC;AAalD,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,8BAA8B;IAC7C,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,SAAS,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC9D,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AA8CD,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,4BAA4B,EACrC,YAAY,GAAE,8BAAoD,GACjE,OAAO,CAAC,SAAS,GAAG,WAAW,CAAC,CAuBlC"}
@@ -0,0 +1,59 @@
1
+ import { readOatConfig, writeOatConfig, } from '../../../config/oat-config.js';
2
+ import { resolveAssetsRoot } from '../../../fs/assets.js';
3
+ import { scanTools } from './scan-tools.js';
4
+ const ALL_PACKS = [
5
+ 'core',
6
+ 'ideas',
7
+ 'docs',
8
+ 'workflows',
9
+ 'utility',
10
+ 'project-management',
11
+ 'research',
12
+ 'brainstorm',
13
+ ];
14
+ const defaultDependencies = {
15
+ resolveAssetsRoot,
16
+ scanTools,
17
+ readOatConfig,
18
+ writeOatConfig,
19
+ };
20
+ function buildProjectToolsConfig(tools) {
21
+ const installedPacks = new Set(tools
22
+ .filter((tool) => tool.scope === 'project' && tool.pack !== 'custom')
23
+ .map((tool) => tool.pack));
24
+ if (installedPacks.size === 0) {
25
+ return undefined;
26
+ }
27
+ return Object.fromEntries(ALL_PACKS.map((pack) => [pack, installedPacks.has(pack)]));
28
+ }
29
+ function toolsConfigEquals(left, right) {
30
+ if (left === undefined || right === undefined) {
31
+ return left === right;
32
+ }
33
+ const leftKeys = Object.keys(left);
34
+ const rightKeys = Object.keys(right);
35
+ return (leftKeys.length === rightKeys.length &&
36
+ ALL_PACKS.every((pack) => left[pack] === right[pack]));
37
+ }
38
+ export async function reconcileProjectToolsConfig(options, dependencies = defaultDependencies) {
39
+ const assetsRoot = await dependencies.resolveAssetsRoot();
40
+ const projectTools = await dependencies.scanTools({
41
+ scope: 'project',
42
+ scopeRoot: options.repoRoot,
43
+ assetsRoot,
44
+ });
45
+ const config = await dependencies.readOatConfig(options.repoRoot);
46
+ const tools = buildProjectToolsConfig(projectTools);
47
+ if (toolsConfigEquals(config.tools, tools)) {
48
+ return 'unchanged';
49
+ }
50
+ const nextConfig = { ...config };
51
+ if (tools === undefined) {
52
+ delete nextConfig.tools;
53
+ }
54
+ else {
55
+ nextConfig.tools = tools;
56
+ }
57
+ await dependencies.writeOatConfig(options.repoRoot, nextConfig);
58
+ return 'written';
59
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/update/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,kCAAkC,CAAC;AAE1C,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAKvE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAE7B,MAAM,gBAAgB,CAAC;AAgBxB,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,GAClD,MAAM,EAAE,CAaV;AAgCD,wBAAgB,wBAAwB,CACtC,YAAY,GAAE,uBAA6C,EAC3D,gBAAgB,GAAE,oBAA8C,GAC/D,OAAO,CAqKT;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAI7E;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,YAAY,GACnB,OAAO,CAOT;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GACd,MAAM,CAMR"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/tools/update/index.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,kCAAkC,CAAC;AAG1C,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAKvE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,uBAAuB,EAE7B,MAAM,gBAAgB,CAAC;AAgBxB,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAAA;CAAE,GAClD,MAAM,EAAE,CAaV;AAgCD,wBAAgB,wBAAwB,CACtC,YAAY,GAAE,uBAA6C,EAC3D,gBAAgB,GAAE,oBAA8C,GAC/D,OAAO,CAmJT;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAI7E;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,YAAY,GACnB,OAAO,CAOT;AAED,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,QAAQ,EACd,MAAM,EAAE,OAAO,GACd,MAAM,CAMR"}
@@ -7,6 +7,7 @@ import { copyDirWithStatus, copyFileWithStatus, } from '../../init/tools/shared/
7
7
  import { withScopeOption } from '../../shared/scope-option.js';
8
8
  import { readGlobalOptions, resolveConcreteScopes, } from '../../shared/shared.utils.js';
9
9
  import { autoSync, } from '../../tools/shared/auto-sync.js';
10
+ import { reconcileProjectToolsConfig } from '../../tools/shared/project-tools-config.js';
10
11
  import { scanTools } from '../../tools/shared/scan-tools.js';
11
12
  import { readOatConfig, writeOatConfig } from '../../../config/oat-config.js';
12
13
  import { resolveAssetsRoot } from '../../../fs/assets.js';
@@ -111,29 +112,17 @@ export function createToolsUpdateCommand(dependencies = defaultDependencies, syn
111
112
  const docsDestination = join(userRoot, '.oat', 'docs');
112
113
  await dependencies.copyDirWithStatus(docsSource, docsDestination, true);
113
114
  }
114
- if (assetsRoot && (target.kind === 'all' || target.kind === 'pack')) {
115
+ if (assetsRoot && result.notInstalled.length === 0) {
115
116
  const repoRoot = await resolveProjectRoot(context.cwd);
116
- const config = await readOatConfig(repoRoot);
117
- const installedPacks = new Set();
118
- const configScopes = resolveConcreteScopes('all');
119
- for (const scope of configScopes) {
120
- const scopeRoot = await dependencies.resolveScopeRoot(scope, context.cwd, context.home);
121
- const tools = await dependencies.scanTools({
122
- scope,
123
- scopeRoot,
124
- assetsRoot,
125
- });
126
- for (const tool of tools) {
127
- if (tool.pack !== 'custom') {
128
- installedPacks.add(tool.pack);
129
- }
130
- }
131
- }
132
- // Preserve unrelated shared config keys while rebuilding tools state
133
- // from the repo-wide installed-pack scan.
134
- await writeOatConfig(repoRoot, {
135
- ...config,
136
- tools: Object.fromEntries(VALID_PACKS.map((pack) => [pack, installedPacks.has(pack)])),
117
+ await reconcileProjectToolsConfig({
118
+ repoRoot,
119
+ cwd: context.cwd,
120
+ home: context.home,
121
+ }, {
122
+ resolveAssetsRoot: dependencies.resolveAssetsRoot,
123
+ scanTools: dependencies.scanTools,
124
+ readOatConfig,
125
+ writeOatConfig,
137
126
  });
138
127
  }
139
128
  if (result.notInstalled.length > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"compute-plan.d.ts","sourceRoot":"","sources":["../../src/engine/compute-plan.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,iCAAiC,CAAC;AAIzC,OAAO,KAAK,EACV,WAAW,EAEX,QAAQ,EAET,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,UAAU,mBAAmB;IAC3B,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AA0dD,wBAAsB,eAAe,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,SAAS,EAAE,iBAAiB,EAC5B,qBAAqB,GACtB,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsIzC"}
1
+ {"version":3,"file":"compute-plan.d.ts","sourceRoot":"","sources":["../../src/engine/compute-plan.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,0BAA0B,CAAC;AACxE,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,iCAAiC,CAAC;AAIzC,OAAO,KAAK,EACV,WAAW,EAEX,QAAQ,EAET,MAAM,gBAAgB,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,UAAU,mBAAmB;IAC3B,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AA0dD,wBAAsB,eAAe,CAAC,EACpC,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,KAAK,EACL,MAAM,EACN,SAAS,EAAE,iBAAiB,EAC5B,qBAAqB,GACtB,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyIzC"}
@@ -5,6 +5,7 @@ import { computeContentHash, computeStringHash } from '../manifest/hash.js';
5
5
  import { findEntry } from '../manifest/manager.js';
6
6
  import { getSyncMappings } from '../providers/shared/adapter.utils.js';
7
7
  import { OAT_DIRECTORY_SENTINEL, OAT_MARKER_PREFIX } from './markers.js';
8
+ import { assertSafeProviderMutationPath } from './provider-path-safety.js';
8
9
  function buildUpLevels(depth) {
9
10
  return Array.from({ length: depth }, () => '..');
10
11
  }
@@ -359,6 +360,7 @@ export async function computeSyncPlan({ canonical, adapters, manifest, scope, co
359
360
  const entryStrategy = mapping.transformCanonical
360
361
  ? 'copy'
361
362
  : (manifestEntry?.strategy ?? mappingStrategy);
363
+ await assertSafeProviderMutationPath(entryScopeRoot, providerPath);
362
364
  const operation = await classifyOperation(canonicalEntry, providerPath, entryStrategy, renderedContent);
363
365
  entries.push({
364
366
  canonical: canonicalEntry,
@@ -392,9 +394,13 @@ export async function computeSyncPlan({ canonical, adapters, manifest, scope, co
392
394
  continue;
393
395
  }
394
396
  const mappingStillExists = (activeMappingsByProvider.get(manifestEntry.provider) ?? []).some((mapping) => manifestEntryInsideMapping(manifestEntry, mapping));
395
- removals.push(mappingStillExists
397
+ const removal = mappingStillExists
396
398
  ? createRemovalEntry(manifestEntry, scopeRoot)
397
- : await classifyObsoleteMappingRetirement(manifestEntry, scopeRoot));
399
+ : await classifyObsoleteMappingRetirement(manifestEntry, scopeRoot);
400
+ if (removal.operation === 'remove') {
401
+ await assertSafeProviderMutationPath(scopeRoot, removal.providerPath);
402
+ }
403
+ removals.push(removal);
398
404
  }
399
405
  return { scope, entries, removals };
400
406
  }
@@ -1,5 +1,9 @@
1
1
  import type { Manifest } from '../manifest/manifest.types.js';
2
2
  import type { SyncPlan, SyncResult } from './engine.types.js';
3
+ interface ExecuteSyncPlanDependencies {
4
+ beforeFirstMutation?: () => Promise<void>;
5
+ }
3
6
  export declare function inferScopeRoot(canonicalPath: string): string;
4
- export declare function executeSyncPlan(plan: SyncPlan, manifest: Manifest, manifestPath: string): Promise<SyncResult>;
7
+ export declare function executeSyncPlan(plan: SyncPlan, manifest: Manifest, manifestPath: string, dependencies?: ExecuteSyncPlanDependencies): Promise<SyncResult>;
8
+ export {};
5
9
  //# sourceMappingURL=execute-plan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"execute-plan.d.ts","sourceRoot":"","sources":["../../src/engine/execute-plan.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,0BAA0B,CAAC;AAExE,OAAO,KAAK,EAAE,QAAQ,EAAiB,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAG1E,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAW5D;AA2JD,wBAAsB,eAAe,CACnC,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,CAAC,CA0BrB"}
1
+ {"version":3,"file":"execute-plan.d.ts","sourceRoot":"","sources":["../../src/engine/execute-plan.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,QAAQ,EAAiB,MAAM,0BAA0B,CAAC;AAExE,OAAO,KAAK,EAAE,QAAQ,EAAiB,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAI1E,UAAU,2BAA2B;IACnC,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3C;AAeD,wBAAgB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAW5D;AA2JD,wBAAsB,eAAe,CACnC,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,MAAM,EACpB,YAAY,GAAE,2BAAoE,GACjF,OAAO,CAAC,UAAU,CAAC,CAwCrB"}
@@ -4,6 +4,15 @@ import { copyDirectory, copySingleFile, createSymlink } from '../fs/io.js';
4
4
  import { computeContentHash, computeStringHash } from '../manifest/hash.js';
5
5
  import { addEntry, findEntry, removeEntry, saveManifest, } from '../manifest/manager.js';
6
6
  import { insertMarker, writeDirectorySentinel } from './markers.js';
7
+ import { assertSafeProviderMutationPath } from './provider-path-safety.js';
8
+ const DEFAULT_EXECUTE_SYNC_PLAN_DEPENDENCIES = {};
9
+ function mutatesProviderPath(entry) {
10
+ return entry.operation !== 'skip' && entry.operation !== 'detach';
11
+ }
12
+ async function assertSafeEntryProviderPath(entry) {
13
+ const scopeRoot = inferScopeRoot(resolve(entry.canonical.canonicalPath));
14
+ await assertSafeProviderMutationPath(scopeRoot, entry.providerPath);
15
+ }
7
16
  export function inferScopeRoot(canonicalPath) {
8
17
  const normalizedPath = canonicalPath.replaceAll('\\', '/');
9
18
  const marker = '/.agents/';
@@ -118,14 +127,20 @@ async function ensureSkipEntryManaged(planEntry, manifest) {
118
127
  const manifestEntry = await toManifestEntry(planEntry, planEntry.strategy);
119
128
  return addEntry(manifest, manifestEntry);
120
129
  }
121
- export async function executeSyncPlan(plan, manifest, manifestPath) {
130
+ export async function executeSyncPlan(plan, manifest, manifestPath, dependencies = DEFAULT_EXECUTE_SYNC_PLAN_DEPENDENCIES) {
122
131
  let nextManifest = manifest;
132
+ let beforeFirstMutationCalled = false;
123
133
  const result = {
124
134
  applied: 0,
125
135
  failed: 0,
126
136
  skipped: 0,
127
137
  };
128
138
  const operations = [...plan.entries, ...plan.removals];
139
+ for (const operation of operations) {
140
+ if (mutatesProviderPath(operation)) {
141
+ await assertSafeEntryProviderPath(operation);
142
+ }
143
+ }
129
144
  for (const operation of operations) {
130
145
  if (operation.operation === 'skip') {
131
146
  nextManifest = await ensureSkipEntryManaged(operation, nextManifest);
@@ -133,6 +148,13 @@ export async function executeSyncPlan(plan, manifest, manifestPath) {
133
148
  continue;
134
149
  }
135
150
  try {
151
+ if (mutatesProviderPath(operation)) {
152
+ if (!beforeFirstMutationCalled) {
153
+ beforeFirstMutationCalled = true;
154
+ await dependencies.beforeFirstMutation?.();
155
+ }
156
+ await assertSafeEntryProviderPath(operation);
157
+ }
136
158
  nextManifest = await applyEntry(operation, nextManifest);
137
159
  result.applied += 1;
138
160
  }
@@ -4,6 +4,7 @@ export { executeSyncPlan } from './execute-plan.js';
4
4
  export { configureLocalHooksPath, getHookInstallInfo, HOOK_DRIFT_WARNING, HOOK_MARKER_END, HOOK_MARKER_START, HOOK_STRAY_INFO, installHook, isHookInstalled, REPO_GITHOOKS_PATH, runHookCheck, uninstallHook, } from './hook.js';
5
5
  export type { HookInstallInfo, HookStatus } from './hook.js';
6
6
  export { hasMarker, insertMarker, OAT_DIRECTORY_SENTINEL, OAT_MARKER_PREFIX, writeDirectorySentinel, } from './markers.js';
7
+ export { assertSafeProviderMutationPath } from './provider-path-safety.js';
7
8
  export type { CanonicalEntry } from './scanner.js';
8
9
  export { scanBundledManagedAgents, scanBundledManagedCodexAgents, scanCanonical, } from './scanner.js';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,GACd,MAAM,QAAQ,CAAC;AAChB,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EACL,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,aAAa,GACd,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,oBAAoB,EACpB,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,aAAa,GACd,MAAM,QAAQ,CAAC;AAChB,YAAY,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EACL,SAAS,EACT,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,8BAA8B,EAAE,MAAM,wBAAwB,CAAC;AACxE,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,aAAa,GACd,MAAM,WAAW,CAAC"}
@@ -3,4 +3,5 @@ export { SYNC_OPERATION_TYPES, } from './engine.types.js';
3
3
  export { executeSyncPlan } from './execute-plan.js';
4
4
  export { configureLocalHooksPath, getHookInstallInfo, HOOK_DRIFT_WARNING, HOOK_MARKER_END, HOOK_MARKER_START, HOOK_STRAY_INFO, installHook, isHookInstalled, REPO_GITHOOKS_PATH, runHookCheck, uninstallHook, } from './hook.js';
5
5
  export { hasMarker, insertMarker, OAT_DIRECTORY_SENTINEL, OAT_MARKER_PREFIX, writeDirectorySentinel, } from './markers.js';
6
+ export { assertSafeProviderMutationPath } from './provider-path-safety.js';
6
7
  export { scanBundledManagedAgents, scanBundledManagedCodexAgents, scanCanonical, } from './scanner.js';
@@ -0,0 +1,2 @@
1
+ export declare function assertSafeProviderMutationPath(scopeRoot: string, providerPath: string): Promise<void>;
2
+ //# sourceMappingURL=provider-path-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-path-safety.d.ts","sourceRoot":"","sources":["../../src/engine/provider-path-safety.ts"],"names":[],"mappings":"AAiBA,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAuDf"}
@@ -0,0 +1,54 @@
1
+ import { lstat } from 'node:fs/promises';
2
+ import { dirname, isAbsolute, relative, resolve, sep } from 'node:path';
3
+ function isMissingPathError(error) {
4
+ return (typeof error === 'object' &&
5
+ error !== null &&
6
+ 'code' in error &&
7
+ error.code === 'ENOENT');
8
+ }
9
+ function displayRelativePath(scopeRoot, path) {
10
+ const relativePath = relative(scopeRoot, path);
11
+ return relativePath || '.';
12
+ }
13
+ export async function assertSafeProviderMutationPath(scopeRoot, providerPath) {
14
+ const resolvedRoot = resolve(scopeRoot);
15
+ const resolvedProviderPath = resolve(providerPath);
16
+ const relativeProviderPath = relative(resolvedRoot, resolvedProviderPath);
17
+ if (relativeProviderPath === '') {
18
+ throw new Error('Provider destination must not equal the sync scope root.');
19
+ }
20
+ if (relativeProviderPath === '..' ||
21
+ relativeProviderPath.startsWith(`..${sep}`) ||
22
+ isAbsolute(relativeProviderPath)) {
23
+ throw new Error(`Provider destination is outside the sync scope: ${providerPath}`);
24
+ }
25
+ const relativeParentPath = dirname(relativeProviderPath);
26
+ const parentSegments = relativeParentPath === '.'
27
+ ? []
28
+ : relativeParentPath.split(sep).filter(Boolean);
29
+ const ancestry = [resolvedRoot];
30
+ let currentPath = resolvedRoot;
31
+ for (const segment of parentSegments) {
32
+ currentPath = resolve(currentPath, segment);
33
+ ancestry.push(currentPath);
34
+ }
35
+ for (const ancestor of ancestry) {
36
+ let stat;
37
+ try {
38
+ stat = await lstat(ancestor);
39
+ }
40
+ catch (error) {
41
+ if (isMissingPathError(error)) {
42
+ return;
43
+ }
44
+ throw error;
45
+ }
46
+ const displayedPath = displayRelativePath(resolvedRoot, ancestor);
47
+ if (stat.isSymbolicLink()) {
48
+ throw new Error(`Unsafe provider parent "${displayedPath}": symbolic links are not allowed in provider ancestry.`);
49
+ }
50
+ if (!stat.isDirectory()) {
51
+ throw new Error(`Unsafe provider parent "${displayedPath}": provider ancestry is not a directory.`);
52
+ }
53
+ }
54
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-agent-toolkit/cli",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "private": false,
5
5
  "description": "Open Agent Toolkit CLI",
6
6
  "homepage": "https://github.com/voxmedia/open-agent-toolkit/tree/main/packages/cli",
@@ -34,7 +34,7 @@
34
34
  "ora": "^9.0.0",
35
35
  "yaml": "2.8.2",
36
36
  "zod": "^3.25.76",
37
- "@open-agent-toolkit/control-plane": "0.2.13"
37
+ "@open-agent-toolkit/control-plane": "0.2.15"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "^22.10.0",