@open-agent-toolkit/cli 0.2.14 → 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.
- package/assets/docs/cli-utilities/config-and-local-state.md +14 -1
- package/assets/docs/cli-utilities/configuration.md +23 -2
- package/assets/docs/cli-utilities/tool-packs.md +43 -17
- package/assets/docs/provider-sync/providers.md +26 -0
- package/assets/docs/reference/troubleshooting.md +42 -0
- package/assets/docs/workflows/projects/lifecycle.md +2 -2
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-agent-instructions-analyze/SKILL.md +2 -2
- package/assets/skills/oat-brainstorm/SKILL.md +8 -8
- package/assets/skills/oat-brainstorm/references/destinations.md +3 -3
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +2 -2
- package/assets/skills/oat-project-document/SKILL.md +4 -4
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +2 -2
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +2 -2
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +2 -2
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +2 -2
- package/assets/skills/oat-project-summary/SKILL.md +9 -9
- package/dist/commands/init/tools/brainstorm/index.d.ts +0 -3
- package/dist/commands/init/tools/brainstorm/index.d.ts.map +1 -1
- package/dist/commands/init/tools/brainstorm/index.js +0 -12
- package/dist/commands/init/tools/index.d.ts.map +1 -1
- package/dist/commands/init/tools/index.js +46 -25
- package/dist/commands/tools/has/has-pack.d.ts +18 -0
- package/dist/commands/tools/has/has-pack.d.ts.map +1 -0
- package/dist/commands/tools/has/has-pack.js +33 -0
- package/dist/commands/tools/has/index.d.ts +4 -0
- package/dist/commands/tools/has/index.d.ts.map +1 -0
- package/dist/commands/tools/has/index.js +57 -0
- package/dist/commands/tools/index.d.ts.map +1 -1
- package/dist/commands/tools/index.js +2 -0
- package/dist/commands/tools/remove/index.d.ts.map +1 -1
- package/dist/commands/tools/remove/index.js +10 -20
- package/dist/commands/tools/shared/project-tools-config.d.ts +16 -0
- package/dist/commands/tools/shared/project-tools-config.d.ts.map +1 -0
- package/dist/commands/tools/shared/project-tools-config.js +59 -0
- package/dist/commands/tools/update/index.d.ts.map +1 -1
- package/dist/commands/tools/update/index.js +11 -22
- package/dist/engine/compute-plan.d.ts.map +1 -1
- package/dist/engine/compute-plan.js +8 -2
- package/dist/engine/execute-plan.d.ts +5 -1
- package/dist/engine/execute-plan.d.ts.map +1 -1
- package/dist/engine/execute-plan.js +23 -1
- package/dist/engine/index.d.ts +1 -0
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +1 -0
- package/dist/engine/provider-path-safety.d.ts +2 -0
- package/dist/engine/provider-path-safety.d.ts.map +1 -0
- package/dist/engine/provider-path-safety.js +54 -0
- package/package.json +2 -2
|
@@ -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;
|
|
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;
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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;
|
|
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 &&
|
|
115
|
+
if (assetsRoot && result.notInstalled.length === 0) {
|
|
115
116
|
const repoRoot = await resolveProjectRoot(context.cwd);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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;
|
|
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
|
-
|
|
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;
|
|
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
|
}
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -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"}
|
package/dist/engine/index.js
CHANGED
|
@@ -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 @@
|
|
|
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.
|
|
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.
|
|
37
|
+
"@open-agent-toolkit/control-plane": "0.2.15"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.10.0",
|