@open-agent-toolkit/cli 0.1.32 → 0.1.34

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 (43) hide show
  1. package/assets/docs/cli-utilities/config-and-local-state.md +21 -1
  2. package/assets/docs/cli-utilities/configuration.md +17 -6
  3. package/assets/docs/cli-utilities/index.md +5 -0
  4. package/assets/docs/cli-utilities/tool-packs.md +1 -1
  5. package/assets/docs/cli-utilities/workflow-gates.md +163 -0
  6. package/assets/docs/contributing/skills.md +25 -0
  7. package/assets/docs/reference/cli-reference.md +17 -14
  8. package/assets/docs/reference/file-locations.md +1 -0
  9. package/assets/docs/reference/oat-directory-structure.md +3 -0
  10. package/assets/public-package-versions.json +4 -4
  11. package/assets/scripts/resolve-tracking.sh +52 -0
  12. package/assets/skills/oat-project-implement/SKILL.md +23 -1
  13. package/assets/skills/oat-project-plan/SKILL.md +23 -1
  14. package/dist/commands/doctor/index.d.ts +4 -1
  15. package/dist/commands/doctor/index.d.ts.map +1 -1
  16. package/dist/commands/doctor/index.js +12 -3
  17. package/dist/commands/gate/index.d.ts +35 -0
  18. package/dist/commands/gate/index.d.ts.map +1 -0
  19. package/dist/commands/gate/index.js +500 -0
  20. package/dist/commands/index.d.ts.map +1 -1
  21. package/dist/commands/index.js +2 -0
  22. package/dist/commands/internal/validate-oat-skills.d.ts +3 -0
  23. package/dist/commands/internal/validate-oat-skills.d.ts.map +1 -1
  24. package/dist/commands/internal/validate-oat-skills.js +44 -2
  25. package/dist/commands/pjm/doctor.d.ts +5 -1
  26. package/dist/commands/pjm/doctor.d.ts.map +1 -1
  27. package/dist/commands/pjm/doctor.js +13 -1
  28. package/dist/commands/pjm/index.d.ts.map +1 -1
  29. package/dist/commands/pjm/index.js +5 -2
  30. package/dist/commands/sync/apply.d.ts.map +1 -1
  31. package/dist/commands/sync/apply.js +6 -2
  32. package/dist/config/oat-config.d.ts +22 -0
  33. package/dist/config/oat-config.d.ts.map +1 -1
  34. package/dist/config/oat-config.js +136 -0
  35. package/dist/config/resolve.d.ts +3 -1
  36. package/dist/config/resolve.d.ts.map +1 -1
  37. package/dist/config/resolve.js +103 -1
  38. package/dist/manifest/manager.d.ts.map +1 -1
  39. package/dist/manifest/manager.js +4 -1
  40. package/dist/validation/skills.d.ts +2 -0
  41. package/dist/validation/skills.d.ts.map +1 -1
  42. package/dist/validation/skills.js +39 -0
  43. package/package.json +2 -2
@@ -1,11 +1,30 @@
1
+ import { join } from 'node:path';
1
2
  import { buildCommandContext, } from '../../app/command-context.js';
2
3
  import { readGlobalOptions } from '../shared/shared.utils.js';
4
+ import { resolveEffectiveConfig as defaultResolveEffectiveConfig, } from '../../config/resolve.js';
3
5
  import { validateOatSkills as defaultValidateOatSkills, } from '../../validation/index.js';
4
6
  import { Command } from 'commander';
5
7
  const DEFAULT_DEPENDENCIES = {
6
8
  buildCommandContext,
7
9
  validateOatSkills: defaultValidateOatSkills,
10
+ resolveEffectiveConfig: defaultResolveEffectiveConfig,
8
11
  };
12
+ function collectConfiguredGateSkillNames(effective) {
13
+ const names = new Set();
14
+ for (const layer of [effective.shared, effective.local, effective.user]) {
15
+ const skills = layer.workflow?.gates?.skills;
16
+ if (!skills) {
17
+ continue;
18
+ }
19
+ for (const skillName of Object.keys(skills)) {
20
+ names.add(skillName);
21
+ }
22
+ }
23
+ return [...names].sort();
24
+ }
25
+ function isBlockingFinding(finding) {
26
+ return finding.severity !== 'warning';
27
+ }
9
28
  function reportFindings(context, result) {
10
29
  if (context.json) {
11
30
  context.logger.json({
@@ -21,14 +40,37 @@ function reportFindings(context, result) {
21
40
  }
22
41
  context.logger.error('\nFix the issues above, then re-run: pnpm oat:validate-skills');
23
42
  }
43
+ function reportWarnings(context, result) {
44
+ if (context.json) {
45
+ context.logger.json({
46
+ status: 'ok',
47
+ validatedSkillCount: result.validatedSkillCount,
48
+ findings: result.findings,
49
+ });
50
+ return;
51
+ }
52
+ context.logger.warn('OAT skill validation warnings:\n');
53
+ for (const finding of result.findings) {
54
+ context.logger.warn(`- ${finding.file}: ${finding.message}`);
55
+ }
56
+ context.logger.info(`OK: validated ${result.validatedSkillCount} oat-* skills`);
57
+ }
24
58
  async function runValidateOatSkills(context, options, dependencies) {
25
59
  try {
26
- const result = await dependencies.validateOatSkills(context.cwd, options);
27
- if (result.findings.length > 0) {
60
+ const effectiveConfig = await dependencies.resolveEffectiveConfig(context.cwd, join(context.home, '.oat'), dependencies.env ?? process.env);
61
+ const gateSkillNames = collectConfiguredGateSkillNames(effectiveConfig);
62
+ const validationOptions = gateSkillNames.length > 0 ? { ...options, gateSkillNames } : options;
63
+ const result = await dependencies.validateOatSkills(context.cwd, validationOptions);
64
+ if (result.findings.some(isBlockingFinding)) {
28
65
  reportFindings(context, result);
29
66
  process.exitCode = 1;
30
67
  return;
31
68
  }
69
+ if (result.findings.length > 0) {
70
+ reportWarnings(context, result);
71
+ process.exitCode = 0;
72
+ return;
73
+ }
32
74
  if (context.json) {
33
75
  context.logger.json({
34
76
  status: 'ok',
@@ -1,3 +1,7 @@
1
1
  import type { DoctorCheck } from '../../ui/output.js';
2
- export declare function runPjmDoctorChecks(repoRoot: string): Promise<DoctorCheck[]>;
2
+ export interface PjmDoctorOptions {
3
+ projectManagementEnabled?: boolean;
4
+ }
5
+ export declare function createPjmDisabledCheck(): DoctorCheck;
6
+ export declare function runPjmDoctorChecks(repoRoot: string, options?: PjmDoctorOptions): Promise<DoctorCheck[]>;
3
7
  //# sourceMappingURL=doctor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/doctor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA0I9C,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,EAAE,CAAC,CAqJxB"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/doctor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA0I9C,MAAM,WAAW,gBAAgB;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,wBAAgB,sBAAsB,IAAI,WAAW,CAQpD;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,WAAW,EAAE,CAAC,CAyJxB"}
@@ -114,7 +114,19 @@ function checkStatus(missing) {
114
114
  function warnStatus(items) {
115
115
  return items.length === 0 ? 'pass' : 'warn';
116
116
  }
117
- export async function runPjmDoctorChecks(repoRoot) {
117
+ export function createPjmDisabledCheck() {
118
+ return {
119
+ name: 'pjm:disabled',
120
+ description: 'Project-management pack enablement',
121
+ status: 'pass',
122
+ message: 'Project-management pack is disabled; PJM checks skipped.',
123
+ fix: 'Run `oat init tools project-management` to install and enable PJM checks.',
124
+ };
125
+ }
126
+ export async function runPjmDoctorChecks(repoRoot, options = {}) {
127
+ if (options.projectManagementEnabled === false) {
128
+ return [createPjmDisabledCheck()];
129
+ }
118
130
  const checks = [];
119
131
  const missingCanonical = [];
120
132
  for (const relativePath of CANONICAL_REPO_REFERENCE_PATHS) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAuB,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAiBnE,UAAU,sBAAsB;IAC9B,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,cAAc,EAAE,OAAO,cAAc,CAAC;IACtC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;CACvD;AA6FD,wBAAgB,gBAAgB,CAC9B,SAAS,GAAE,OAAO,CAAC,sBAAsB,CAAM,GAC9C,OAAO,CAkJT"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/pjm/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAuB,MAAM,sBAAsB,CAAC;AAEhF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAiBnE,UAAU,sBAAsB;IAC9B,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,aAAa,EAAE,OAAO,aAAa,CAAC;IACpC,uBAAuB,EAAE,OAAO,uBAAuB,CAAC;IACxD,kBAAkB,EAAE,OAAO,kBAAkB,CAAC;IAC9C,cAAc,EAAE,OAAO,cAAc,CAAC;IACtC,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;CACvD;AA6FD,wBAAgB,gBAAgB,CAC9B,SAAS,GAAE,OAAO,CAAC,sBAAsB,CAAM,GAC9C,OAAO,CAsJT"}
@@ -120,14 +120,17 @@ export function createPjmCommand(overrides = {}) {
120
120
  });
121
121
  cmd
122
122
  .command('doctor')
123
- .description('Run PJM repo reference diagnostics')
123
+ .description('Run PJM repo reference diagnostics when enabled')
124
124
  .option('--repo-root <path>', 'PJM repo reference root directory (defaults to .oat/repo)')
125
125
  .action(async (options, command) => {
126
126
  const context = dependencies.buildCommandContext(readGlobalOptions(command));
127
127
  try {
128
128
  const projectRoot = await dependencies.resolveProjectRoot(context.cwd);
129
129
  const repoRoot = await resolveRepoRoot(context, projectRoot, options.repoRoot);
130
- const checks = await dependencies.runPjmDoctorChecks(repoRoot);
130
+ const config = await dependencies.readOatConfig(projectRoot);
131
+ const checks = await dependencies.runPjmDoctorChecks(repoRoot, {
132
+ projectManagementEnabled: config.tools?.['project-management'] === true,
133
+ });
131
134
  const status = doctorStatus(checks);
132
135
  if (context.json) {
133
136
  context.logger.json({ status, repoRoot, checks });
@@ -1 +1 @@
1
- {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EAExB,MAAM,cAAc,CAAC;AAgEtB,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,aAAa,EAAE,EAC3B,YAAY,EAAE,uBAAuB,GACpC,OAAO,CAAC,IAAI,CAAC,CAwEf"}
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EAExB,MAAM,cAAc,CAAC;AAgEtB,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,aAAa,EAAE,EAC3B,YAAY,EAAE,uBAAuB,GACpC,OAAO,CAAC,IAAI,CAAC,CA8Ef"}
@@ -1,3 +1,4 @@
1
+ import { OAT_VERSION } from '../../shared/oat-version.js';
1
2
  import { countPlannedOperations } from './sync.utils.js';
2
3
  function countSkippedEntries(scopePlans) {
3
4
  return scopePlans.reduce((total, scopePlan) => {
@@ -45,10 +46,13 @@ export async function runSyncApply(context, scopePlans, dependencies) {
45
46
  for (const scopePlan of scopePlans) {
46
47
  const hasSyncEntries = scopePlan.plan.entries.length > 0 || scopePlan.plan.removals.length > 0;
47
48
  const hasCodexPlannedOperations = scopePlan.codexExtensionPlan?.operations.some((operation) => operation.action !== 'skip') ?? false;
48
- if (!hasSyncEntries && !hasCodexPlannedOperations) {
49
+ const shouldRefreshManifestVersion = scopePlan.manifest.oatVersion !== OAT_VERSION;
50
+ if (!hasSyncEntries &&
51
+ !hasCodexPlannedOperations &&
52
+ !shouldRefreshManifestVersion) {
49
53
  continue;
50
54
  }
51
- if (hasSyncEntries) {
55
+ if (hasSyncEntries || shouldRefreshManifestVersion) {
52
56
  const result = await dependencies.executeSyncPlan(scopePlan.plan, scopePlan.manifest, scopePlan.manifestPath);
53
57
  applied += result.applied;
54
58
  failed += result.failed;
@@ -23,6 +23,8 @@ export type WorkflowDesignMode = 'collaborative' | 'selective' | 'draft';
23
23
  export type WorkflowCodexDispatchCeiling = 'low' | 'medium' | 'high' | 'xhigh';
24
24
  export type WorkflowClaudeDispatchCeiling = 'haiku' | 'sonnet' | 'opus';
25
25
  export type WorkflowDispatchCeilingPreset = 'balanced' | 'maximum' | 'cost-conscious';
26
+ export type GateOnFailure = 'block' | 'prompt' | 'warn';
27
+ export type GateAvoid = 'same-runtime' | 'none';
26
28
  export interface WorkflowDispatchCeiling {
27
29
  preset?: WorkflowDispatchCeilingPreset;
28
30
  providers?: {
@@ -34,6 +36,24 @@ export interface WorkflowAutoArtifactReview {
34
36
  plan?: boolean;
35
37
  analysis?: boolean;
36
38
  }
39
+ export interface GateConfig {
40
+ command: string;
41
+ onFailure: GateOnFailure;
42
+ description?: string;
43
+ maxAttempts?: number;
44
+ }
45
+ export interface ExecTarget {
46
+ runtime: string;
47
+ baseCommand: string[];
48
+ hostDetectionCommand?: string[];
49
+ availabilityCommand?: string[];
50
+ priority: number;
51
+ }
52
+ export type ExecTargetConfig = Partial<ExecTarget>;
53
+ export interface WorkflowGatesConfig {
54
+ execTargets?: Record<string, ExecTargetConfig | null>;
55
+ skills?: Record<string, GateConfig | null>;
56
+ }
37
57
  export interface OatWorkflowConfig {
38
58
  hillCheckpointDefault?: WorkflowHillCheckpointDefault;
39
59
  archiveOnComplete?: boolean;
@@ -45,10 +65,12 @@ export interface OatWorkflowConfig {
45
65
  autoArtifactReview?: WorkflowAutoArtifactReview;
46
66
  designMode?: WorkflowDesignMode;
47
67
  dispatchCeiling?: WorkflowDispatchCeiling;
68
+ gates?: WorkflowGatesConfig;
48
69
  }
49
70
  export declare const VALID_CODEX_DISPATCH_CEILINGS: readonly WorkflowCodexDispatchCeiling[];
50
71
  export declare const VALID_CLAUDE_DISPATCH_CEILINGS: readonly WorkflowClaudeDispatchCeiling[];
51
72
  export declare const VALID_DISPATCH_CEILING_PRESETS: readonly WorkflowDispatchCeilingPreset[];
73
+ export declare const BUILTIN_EXEC_TARGETS: Readonly<Record<string, ExecTarget>>;
52
74
  export type OatToolsConfig = Partial<Record<'core' | 'ideas' | 'docs' | 'workflows' | 'utility' | 'project-management' | 'research' | 'brainstorm', boolean>>;
53
75
  export interface OatConfig {
54
76
  version: number;
@@ -1 +1 @@
1
- {"version":3,"file":"oat-config.d.ts","sourceRoot":"","sources":["../../src/config/oat-config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oat-config.d.ts","sourceRoot":"","sources":["../../src/config/oat-config.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,128 @@ const VALID_DESIGN_MODES = [
19
19
  export const VALID_CODEX_DISPATCH_CEILINGS = ['low', 'medium', 'high', 'xhigh'];
20
20
  export const VALID_CLAUDE_DISPATCH_CEILINGS = ['haiku', 'sonnet', 'opus'];
21
21
  export const VALID_DISPATCH_CEILING_PRESETS = ['balanced', 'maximum', 'cost-conscious'];
22
+ const VALID_GATE_ON_FAILURES = [
23
+ 'block',
24
+ 'prompt',
25
+ 'warn',
26
+ ];
27
+ export const BUILTIN_EXEC_TARGETS = {
28
+ 'codex-default': {
29
+ runtime: 'codex',
30
+ baseCommand: ['codex', 'exec'],
31
+ hostDetectionCommand: [
32
+ 'sh',
33
+ '-c',
34
+ '[ -n "$CODEX_THREAD_ID" ] || [ -n "$CODEX_SESSION_ID" ]',
35
+ ],
36
+ availabilityCommand: ['codex', '--version'],
37
+ priority: 100,
38
+ },
39
+ 'claude-default': {
40
+ runtime: 'claude',
41
+ baseCommand: ['claude', '-p'],
42
+ hostDetectionCommand: ['sh', '-c', 'test -n "$CLAUDECODE"'],
43
+ availabilityCommand: ['claude', '--version'],
44
+ priority: 100,
45
+ },
46
+ 'cursor-default': {
47
+ runtime: 'cursor',
48
+ baseCommand: ['cursor-agent', '-p', '--force'],
49
+ hostDetectionCommand: ['sh', '-c', 'test -n "$CURSOR_AGENT"'],
50
+ availabilityCommand: ['cursor-agent', '--version'],
51
+ priority: 70,
52
+ },
53
+ };
54
+ function normalizeMaxAttempts(value) {
55
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
56
+ return 2;
57
+ }
58
+ const attempts = Math.trunc(value);
59
+ return attempts >= 1 ? attempts : 2;
60
+ }
61
+ function normalizeArgv(value) {
62
+ if (!Array.isArray(value) ||
63
+ value.length === 0 ||
64
+ !value.every((item) => typeof item === 'string')) {
65
+ return undefined;
66
+ }
67
+ const [executable] = value;
68
+ if (executable === undefined || !executable.trim()) {
69
+ return undefined;
70
+ }
71
+ return [...value];
72
+ }
73
+ function normalizeGateConfig(value) {
74
+ if (value === null) {
75
+ return null;
76
+ }
77
+ if (!isRecord(value)) {
78
+ return undefined;
79
+ }
80
+ const command = trimNonEmptyString(value.command);
81
+ if (command === undefined ||
82
+ typeof value.onFailure !== 'string' ||
83
+ !VALID_GATE_ON_FAILURES.includes(value.onFailure)) {
84
+ return undefined;
85
+ }
86
+ const gate = {
87
+ command,
88
+ onFailure: value.onFailure,
89
+ maxAttempts: normalizeMaxAttempts(value.maxAttempts),
90
+ };
91
+ const description = trimNonEmptyString(value.description);
92
+ if (description !== undefined) {
93
+ gate.description = description;
94
+ }
95
+ return gate;
96
+ }
97
+ function normalizeExecTarget(value) {
98
+ if (value === null) {
99
+ return null;
100
+ }
101
+ if (!isRecord(value)) {
102
+ return undefined;
103
+ }
104
+ const target = {};
105
+ const runtime = trimNonEmptyString(value.runtime);
106
+ if (runtime !== undefined) {
107
+ target.runtime = runtime;
108
+ }
109
+ const baseCommand = normalizeArgv(value.baseCommand);
110
+ if (baseCommand !== undefined) {
111
+ target.baseCommand = baseCommand;
112
+ }
113
+ if ('priority' in value) {
114
+ if (typeof value.priority === 'number' && Number.isFinite(value.priority)) {
115
+ target.priority = value.priority;
116
+ }
117
+ }
118
+ const hostDetectionCommand = normalizeArgv(value.hostDetectionCommand);
119
+ if (hostDetectionCommand !== undefined) {
120
+ target.hostDetectionCommand = hostDetectionCommand;
121
+ }
122
+ const availabilityCommand = normalizeArgv(value.availabilityCommand);
123
+ if (availabilityCommand !== undefined) {
124
+ target.availabilityCommand = availabilityCommand;
125
+ }
126
+ return Object.keys(target).length > 0 ? target : undefined;
127
+ }
128
+ function normalizeRecordMap(value, normalizeValue) {
129
+ if (!isRecord(value)) {
130
+ return undefined;
131
+ }
132
+ const next = {};
133
+ for (const [key, rawEntry] of Object.entries(value)) {
134
+ if (!key.trim()) {
135
+ continue;
136
+ }
137
+ const normalized = normalizeValue(rawEntry);
138
+ if (normalized !== undefined) {
139
+ next[key] = normalized;
140
+ }
141
+ }
142
+ return Object.keys(next).length > 0 ? next : undefined;
143
+ }
22
144
  function normalizeWorkflowConfig(parsed) {
23
145
  if (!isRecord(parsed)) {
24
146
  return undefined;
@@ -94,6 +216,20 @@ function normalizeWorkflowConfig(parsed) {
94
216
  next.dispatchCeiling = dispatchCeiling;
95
217
  }
96
218
  }
219
+ if (isRecord(parsed.gates)) {
220
+ const gates = {};
221
+ const execTargets = normalizeRecordMap(parsed.gates.execTargets, normalizeExecTarget);
222
+ if (execTargets !== undefined) {
223
+ gates.execTargets = execTargets;
224
+ }
225
+ const skills = normalizeRecordMap(parsed.gates.skills, normalizeGateConfig);
226
+ if (skills !== undefined) {
227
+ gates.skills = skills;
228
+ }
229
+ if (Object.keys(gates).length > 0) {
230
+ next.gates = gates;
231
+ }
232
+ }
97
233
  return Object.keys(next).length > 0 ? next : undefined;
98
234
  }
99
235
  const DEFAULT_OAT_CONFIG = { version: 1 };
@@ -1,4 +1,4 @@
1
- import { type OatConfig, type OatLocalConfig, type UserConfig } from './oat-config.js';
1
+ import { type ExecTarget, type GateConfig, type OatConfig, type OatLocalConfig, type UserConfig } from './oat-config.js';
2
2
  export type ResolvedConfigSource = 'shared' | 'local' | 'user' | 'env' | 'default';
3
3
  export interface ResolvedKeyEntry {
4
4
  value: unknown;
@@ -16,4 +16,6 @@ export interface ResolveEffectiveConfigDependencies {
16
16
  readUserConfig: (userConfigDir: string) => Promise<UserConfig>;
17
17
  }
18
18
  export declare function resolveEffectiveConfig(repoRoot: string, userConfigDir: string, env?: NodeJS.ProcessEnv, overrides?: Partial<ResolveEffectiveConfigDependencies>): Promise<ResolvedConfig>;
19
+ export declare function resolveGate(effective: ResolvedConfig, skillName: string): GateConfig | null;
20
+ export declare function resolveExecTargets(effective: ResolvedConfig): Record<string, ExecTarget>;
19
21
  //# sourceMappingURL=resolve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAkC;IACjD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAChE;AA+ED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CAAC,cAAc,CAAC,CAgFzB"}
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/config/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,GACR,OAAO,GACP,MAAM,GACN,KAAK,GACL,SAAS,CAAC;AAEd,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,oBAAoB,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,kCAAkC;IACjD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CAChE;AA+ED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CAAC,cAAc,CAAC,CAgFzB;AAED,wBAAgB,WAAW,CACzB,SAAS,EAAE,cAAc,EACzB,SAAS,EAAE,MAAM,GAChB,UAAU,GAAG,IAAI,CAcnB;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,GACxB,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAY5B"}
@@ -1,4 +1,4 @@
1
- import { readOatConfig, readOatLocalConfig, readUserConfig, } from './oat-config.js';
1
+ import { BUILTIN_EXEC_TARGETS, readOatConfig, readOatLocalConfig, readUserConfig, } from './oat-config.js';
2
2
  const DEFAULT_DEPENDENCIES = {
3
3
  readOatConfig,
4
4
  readOatLocalConfig,
@@ -139,6 +139,105 @@ export async function resolveEffectiveConfig(repoRoot, userConfigDir, env = proc
139
139
  resolved,
140
140
  };
141
141
  }
142
+ export function resolveGate(effective, skillName) {
143
+ for (const skills of [
144
+ effective.local.workflow?.gates?.skills,
145
+ effective.shared.workflow?.gates?.skills,
146
+ effective.user.workflow?.gates?.skills,
147
+ ]) {
148
+ if (!skills || !hasOwn(skills, skillName)) {
149
+ continue;
150
+ }
151
+ return skills[skillName] ?? null;
152
+ }
153
+ return null;
154
+ }
155
+ export function resolveExecTargets(effective) {
156
+ const targets = cloneExecTargetRegistry(BUILTIN_EXEC_TARGETS);
157
+ for (const execTargets of [
158
+ effective.user.workflow?.gates?.execTargets,
159
+ effective.shared.workflow?.gates?.execTargets,
160
+ effective.local.workflow?.gates?.execTargets,
161
+ ]) {
162
+ mergeExecTargetLayer(targets, execTargets);
163
+ }
164
+ return targets;
165
+ }
166
+ function mergeExecTargetLayer(targets, layer) {
167
+ if (!layer) {
168
+ return;
169
+ }
170
+ for (const [id, override] of Object.entries(layer)) {
171
+ if (override === null) {
172
+ delete targets[id];
173
+ continue;
174
+ }
175
+ const existing = targets[id];
176
+ if (existing) {
177
+ targets[id] = cloneExecTarget({
178
+ runtime: override.runtime ?? existing.runtime,
179
+ baseCommand: override.baseCommand ?? existing.baseCommand,
180
+ hostDetectionCommand: override.hostDetectionCommand ?? existing.hostDetectionCommand,
181
+ availabilityCommand: override.availabilityCommand ?? existing.availabilityCommand,
182
+ priority: override.priority ?? existing.priority,
183
+ });
184
+ continue;
185
+ }
186
+ const completeTarget = toCompleteExecTarget(override);
187
+ if (completeTarget) {
188
+ targets[id] = completeTarget;
189
+ }
190
+ }
191
+ }
192
+ function cloneExecTargetRegistry(registry) {
193
+ return Object.fromEntries(Object.entries(registry).map(([id, target]) => [
194
+ id,
195
+ cloneExecTarget(target),
196
+ ]));
197
+ }
198
+ function cloneExecTarget(target) {
199
+ const next = {
200
+ runtime: target.runtime,
201
+ baseCommand: [...target.baseCommand],
202
+ priority: target.priority,
203
+ };
204
+ if (target.hostDetectionCommand) {
205
+ next.hostDetectionCommand = [...target.hostDetectionCommand];
206
+ }
207
+ if (target.availabilityCommand) {
208
+ next.availabilityCommand = [...target.availabilityCommand];
209
+ }
210
+ return next;
211
+ }
212
+ function toCompleteExecTarget(target) {
213
+ const runtime = typeof target.runtime === 'string' ? target.runtime.trim() : '';
214
+ if (!runtime || !isValidArgv(target.baseCommand)) {
215
+ return null;
216
+ }
217
+ const completeTarget = {
218
+ runtime,
219
+ baseCommand: [...target.baseCommand],
220
+ priority: typeof target.priority === 'number' && Number.isFinite(target.priority)
221
+ ? target.priority
222
+ : 0,
223
+ };
224
+ if (isValidArgv(target.hostDetectionCommand)) {
225
+ completeTarget.hostDetectionCommand = [...target.hostDetectionCommand];
226
+ }
227
+ if (isValidArgv(target.availabilityCommand)) {
228
+ completeTarget.availabilityCommand = [...target.availabilityCommand];
229
+ }
230
+ return completeTarget;
231
+ }
232
+ function isValidArgv(value) {
233
+ if (!Array.isArray(value) ||
234
+ value.length === 0 ||
235
+ !value.every((part) => typeof part === 'string')) {
236
+ return false;
237
+ }
238
+ const [executable] = value;
239
+ return executable !== undefined && executable.trim().length > 0;
240
+ }
142
241
  function flattenConfig(value, prefix = '') {
143
242
  if (!isRecord(value)) {
144
243
  return {};
@@ -168,6 +267,9 @@ function resolveEnvOverride(key, env) {
168
267
  function isRecord(value) {
169
268
  return typeof value === 'object' && value !== null && !Array.isArray(value);
170
269
  }
270
+ function hasOwn(value, key) {
271
+ return Object.prototype.hasOwnProperty.call(value, key);
272
+ }
171
273
  function isResolvedValue(value) {
172
274
  return value !== undefined && value !== null;
173
275
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/manifest/manager.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,aAAa,EAEnB,MAAM,kBAAkB,CAAC;AAa1B,wBAAgB,mBAAmB,IAAI,QAAQ,CAO9C;AAED,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6C1E;AAED,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAgB,SAAS,CACvB,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,aAAa,GAAG,SAAS,CAK3B;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,CAc3E;AAED,wBAAgB,WAAW,CACzB,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,QAAQ,CAeV"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/manifest/manager.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,QAAQ,EACb,KAAK,aAAa,EAEnB,MAAM,kBAAkB,CAAC;AAa1B,wBAAgB,mBAAmB,IAAI,QAAQ,CAO9C;AAED,wBAAsB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6C1E;AAED,wBAAsB,YAAY,CAChC,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAgB,SAAS,CACvB,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,aAAa,GAAG,SAAS,CAK3B;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,CAc3E;AAED,wBAAgB,WAAW,CACzB,QAAQ,EAAE,QAAQ,EAClB,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,QAAQ,CAeV"}
@@ -54,7 +54,10 @@ export async function loadManifest(manifestPath) {
54
54
  }
55
55
  }
56
56
  export async function saveManifest(manifestPath, manifest) {
57
- const validated = ManifestSchema.parse(manifest);
57
+ const validated = ManifestSchema.parse({
58
+ ...manifest,
59
+ oatVersion: OAT_VERSION,
60
+ });
58
61
  const dir = dirname(manifestPath);
59
62
  const tempPath = `${manifestPath}.${randomUUID()}.tmp`;
60
63
  await mkdir(dir, { recursive: true });
@@ -1,6 +1,7 @@
1
1
  export interface ValidationFinding {
2
2
  file: string;
3
3
  message: string;
4
+ severity?: 'error' | 'warning';
4
5
  }
5
6
  export interface ValidateOatSkillsResult {
6
7
  validatedSkillCount: number;
@@ -15,6 +16,7 @@ export interface ValidateChangedSkillVersionBumpsResult {
15
16
  }
16
17
  export interface ValidateOatSkillsOptions {
17
18
  baseRef?: string;
19
+ gateSkillNames?: readonly string[];
18
20
  }
19
21
  export type ExecFileResult = {
20
22
  stdout: string;
@@ -1 +1 @@
1
- {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/validation/skills.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,uCAAuC;IACtD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sCAAsC;IACrD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KAChD,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,UAAU,6BAA6B;IACrC,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAmPD,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uCAAuC,EAChD,YAAY,GAAE,6BAAkC,GAC/C,OAAO,CAAC,sCAAsC,CAAC,CAoBjD;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,EACtC,YAAY,GAAE,6BAAkC,GAC/C,OAAO,CAAC,uBAAuB,CAAC,CA6HlC"}
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/validation/skills.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,uCAAuC;IACtD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sCAAsC;IACrD,mBAAmB,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAE,KAChD,OAAO,CAAC,cAAc,CAAC,CAAC;AAE7B,UAAU,6BAA6B;IACrC,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAuSD,wBAAsB,gCAAgC,CACpD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uCAAuC,EAChD,YAAY,GAAE,6BAAkC,GAC/C,OAAO,CAAC,sCAAsC,CAAC,CAoBjD;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,wBAA6B,EACtC,YAAY,GAAE,6BAAkC,GAC/C,OAAO,CAAC,uBAAuB,CAAC,CAmIlC"}
@@ -22,6 +22,10 @@ function getFrontmatterScalar(frontmatter, key) {
22
22
  const match = frontmatter.match(re);
23
23
  return match?.[1]?.trim() ?? null;
24
24
  }
25
+ function hasTrueFrontmatterValue(frontmatter, key) {
26
+ return (frontmatterHasKey(frontmatter, key) &&
27
+ getFrontmatterScalar(frontmatter, key) === 'true');
28
+ }
25
29
  function isValidSemver(value) {
26
30
  return /^\d+\.\d+\.\d+$/.test(value);
27
31
  }
@@ -87,6 +91,40 @@ function validateQuickStartSemantics(skillPath, content, findings) {
87
91
  });
88
92
  }
89
93
  }
94
+ function normalizeGateSkillNames(gateSkillNames) {
95
+ if (!gateSkillNames) {
96
+ return [];
97
+ }
98
+ return [
99
+ ...new Set(gateSkillNames.map((name) => name.trim()).filter(Boolean)),
100
+ ].sort();
101
+ }
102
+ async function collectGateabilityFindings(skillsRoot, gateSkillNames, findings) {
103
+ for (const skillName of normalizeGateSkillNames(gateSkillNames)) {
104
+ const skillPath = join(skillsRoot, skillName, 'SKILL.md');
105
+ let content;
106
+ try {
107
+ content = await readFile(skillPath, 'utf8');
108
+ }
109
+ catch {
110
+ findings.push({
111
+ file: skillPath,
112
+ message: `Configured gate targets unknown skill: ${skillName}`,
113
+ severity: 'warning',
114
+ });
115
+ continue;
116
+ }
117
+ const frontmatter = getFrontmatterBlock(content);
118
+ if (frontmatter === null ||
119
+ !hasTrueFrontmatterValue(frontmatter, 'oat_gateable')) {
120
+ findings.push({
121
+ file: skillPath,
122
+ message: 'Configured gate targets skill without oat_gateable: true',
123
+ severity: 'warning',
124
+ });
125
+ }
126
+ }
127
+ }
90
128
  async function listChangedSkillFiles(repoRoot, baseRef, dependencies) {
91
129
  const execFile = dependencies.gitExecFile ?? execFileAsync;
92
130
  const { stdout } = await execFile('git', [
@@ -261,6 +299,7 @@ export async function validateOatSkills(repoRoot, options = {}, dependencies = {
261
299
  validateQuickStartSemantics(skillPath, content, findings);
262
300
  }
263
301
  }
302
+ await collectGateabilityFindings(skillsRoot, options.gateSkillNames, findings);
264
303
  if (options.baseRef) {
265
304
  const changedSkillFiles = await listChangedSkillFiles(repoRoot, options.baseRef, dependencies);
266
305
  await collectChangedSkillVersionBumpFindings(repoRoot, options.baseRef, changedSkillFiles, findings, dependencies);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-agent-toolkit/cli",
3
- "version": "0.1.32",
3
+ "version": "0.1.34",
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.1.32"
37
+ "@open-agent-toolkit/control-plane": "0.1.34"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/node": "^22.10.0",