@open-agent-toolkit/cli 0.0.26 → 0.0.28
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/configuration.md +108 -0
- package/assets/docs/reference/cli-reference.md +25 -0
- package/assets/docs/workflows/projects/hill-checkpoints.md +17 -0
- package/assets/docs/workflows/projects/lifecycle.md +6 -0
- package/assets/docs/workflows/projects/reviews.md +24 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-project-complete/SKILL.md +20 -1
- package/assets/skills/oat-project-implement/SKILL.md +85 -4
- package/assets/skills/oat-project-review-provide/SKILL.md +12 -2
- package/assets/skills/oat-project-review-receive/SKILL.md +23 -1
- package/assets/skills/oat-project-review-receive-remote/SKILL.md +17 -1
- package/dist/commands/config/index.d.ts +5 -1
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +268 -140
- package/dist/config/oat-config.d.ts +14 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +50 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +20 -0
- package/dist/release/public-package-contract.d.ts +2 -1
- package/dist/release/public-package-contract.d.ts.map +1 -1
- package/dist/release/public-package-contract.js +28 -0
- package/package.json +2 -2
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
1
2
|
import { buildCommandContext } from '../../app/command-context.js';
|
|
2
3
|
import { resolveProjectsRoot } from '../shared/oat-paths.js';
|
|
3
4
|
import { readGlobalOptions } from '../shared/shared.utils.js';
|
|
4
|
-
import { readOatConfig, readOatLocalConfig, writeOatConfig, writeOatLocalConfig, } from '../../config/oat-config.js';
|
|
5
|
+
import { readOatConfig, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, } from '../../config/oat-config.js';
|
|
6
|
+
import { resolveEffectiveConfig, } from '../../config/resolve.js';
|
|
5
7
|
import { resolveProjectRoot } from '../../fs/paths.js';
|
|
6
8
|
import { Command } from 'commander';
|
|
7
9
|
import { createConfigDumpCommand } from './dump.js';
|
|
@@ -26,6 +28,12 @@ const KEY_ORDER = [
|
|
|
26
28
|
'tools.research',
|
|
27
29
|
'tools.utility',
|
|
28
30
|
'tools.workflows',
|
|
31
|
+
'workflow.hillCheckpointDefault',
|
|
32
|
+
'workflow.archiveOnComplete',
|
|
33
|
+
'workflow.createPrOnComplete',
|
|
34
|
+
'workflow.postImplementSequence',
|
|
35
|
+
'workflow.reviewExecutionModel',
|
|
36
|
+
'workflow.autoNarrowReReviewScope',
|
|
29
37
|
'worktrees.root',
|
|
30
38
|
];
|
|
31
39
|
const CONFIG_CATALOG = [
|
|
@@ -268,8 +276,74 @@ const CONFIG_CATALOG = [
|
|
|
268
276
|
type: 'string | null',
|
|
269
277
|
defaultValue: 'null',
|
|
270
278
|
mutability: 'read/write',
|
|
271
|
-
owningCommand: '
|
|
272
|
-
description: 'User-level active idea fallback when no repo-local active idea is set.',
|
|
279
|
+
owningCommand: 'oat config set activeIdea <value> --user',
|
|
280
|
+
description: 'User-level active idea fallback used when no repo-local active idea is set. Writable via `oat config set activeIdea <value> --user`.',
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
key: 'workflow.hillCheckpointDefault',
|
|
284
|
+
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
285
|
+
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
286
|
+
scope: 'workflow',
|
|
287
|
+
type: 'every | final',
|
|
288
|
+
defaultValue: 'unset',
|
|
289
|
+
mutability: 'read/write',
|
|
290
|
+
owningCommand: 'oat config set workflow.hillCheckpointDefault <value>',
|
|
291
|
+
description: 'Default HiLL checkpoint behavior in oat-project-implement: "every" pauses after every phase, "final" pauses only after the last phase. When unset, the skill prompts. Resolution: env > local > shared > user > default.',
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
key: 'workflow.archiveOnComplete',
|
|
295
|
+
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
296
|
+
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
297
|
+
scope: 'workflow',
|
|
298
|
+
type: 'boolean',
|
|
299
|
+
defaultValue: 'unset',
|
|
300
|
+
mutability: 'read/write',
|
|
301
|
+
owningCommand: 'oat config set workflow.archiveOnComplete <true|false>',
|
|
302
|
+
description: 'Skip the "Archive after completion?" prompt in oat-project-complete. When unset, the skill prompts. Resolution: env > local > shared > user > default.',
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
key: 'workflow.createPrOnComplete',
|
|
306
|
+
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
307
|
+
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
308
|
+
scope: 'workflow',
|
|
309
|
+
type: 'boolean',
|
|
310
|
+
defaultValue: 'unset',
|
|
311
|
+
mutability: 'read/write',
|
|
312
|
+
owningCommand: 'oat config set workflow.createPrOnComplete <true|false>',
|
|
313
|
+
description: 'Skip the "Open a PR?" prompt in oat-project-complete. When true, completion auto-triggers PR creation. Resolution: env > local > shared > user > default.',
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
key: 'workflow.postImplementSequence',
|
|
317
|
+
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
318
|
+
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
319
|
+
scope: 'workflow',
|
|
320
|
+
type: 'wait | summary | pr | docs-pr',
|
|
321
|
+
defaultValue: 'unset',
|
|
322
|
+
mutability: 'read/write',
|
|
323
|
+
owningCommand: 'oat config set workflow.postImplementSequence <value>',
|
|
324
|
+
description: 'Default post-implementation chaining: "wait" stops without auto-chaining, "summary" generates summary only, "pr" runs pr-final (which auto-generates summary), "docs-pr" runs docs sync then pr-final. When unset, the skill prompts. Resolution: env > local > shared > user > default.',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
key: 'workflow.reviewExecutionModel',
|
|
328
|
+
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
329
|
+
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
330
|
+
scope: 'workflow',
|
|
331
|
+
type: 'subagent | inline | fresh-session',
|
|
332
|
+
defaultValue: 'unset',
|
|
333
|
+
mutability: 'read/write',
|
|
334
|
+
owningCommand: 'oat config set workflow.reviewExecutionModel <value>',
|
|
335
|
+
description: 'Default execution model for the final review step in oat-project-implement: "subagent" dispatches a review subagent, "inline" runs the review in-context, "fresh-session" prints guidance for running the review in a separate session (with an escape hatch to subagent/inline). When unset, the skill prompts. Resolution: env > local > shared > user > default.',
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
key: 'workflow.autoNarrowReReviewScope',
|
|
339
|
+
group: 'Workflow Preferences (3-layer: local > shared > user)',
|
|
340
|
+
file: '.oat/config.local.json | .oat/config.json | ~/.oat/config.json',
|
|
341
|
+
scope: 'workflow',
|
|
342
|
+
type: 'boolean',
|
|
343
|
+
defaultValue: 'unset',
|
|
344
|
+
mutability: 'read/write',
|
|
345
|
+
owningCommand: 'oat config set workflow.autoNarrowReReviewScope <true|false>',
|
|
346
|
+
description: 'Auto-narrow re-review scope to fix-task commits in oat-project-review-provide when re-reviewing completed fix tasks. Has no effect on initial reviews (there is nothing to narrow to). When unset, the skill prompts. Resolution: env > local > shared > user > default.',
|
|
273
347
|
},
|
|
274
348
|
{
|
|
275
349
|
key: 'sync.defaultStrategy',
|
|
@@ -312,7 +386,10 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
312
386
|
writeOatConfig,
|
|
313
387
|
readOatLocalConfig,
|
|
314
388
|
writeOatLocalConfig,
|
|
389
|
+
readUserConfig,
|
|
390
|
+
writeUserConfig,
|
|
315
391
|
resolveProjectsRoot,
|
|
392
|
+
resolveEffectiveConfig,
|
|
316
393
|
processEnv: process.env,
|
|
317
394
|
};
|
|
318
395
|
function isConfigKey(value) {
|
|
@@ -325,150 +402,168 @@ function normalizeSharedRoot(value) {
|
|
|
325
402
|
}
|
|
326
403
|
return trimmed.replace(/\/+$/, '');
|
|
327
404
|
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
405
|
+
const WORKFLOW_ENUM_VALUES = {
|
|
406
|
+
'workflow.hillCheckpointDefault': ['every', 'final'],
|
|
407
|
+
'workflow.postImplementSequence': ['wait', 'summary', 'pr', 'docs-pr'],
|
|
408
|
+
'workflow.reviewExecutionModel': ['subagent', 'inline', 'fresh-session'],
|
|
409
|
+
};
|
|
410
|
+
const WORKFLOW_BOOLEAN_KEYS = new Set([
|
|
411
|
+
'workflow.archiveOnComplete',
|
|
412
|
+
'workflow.createPrOnComplete',
|
|
413
|
+
'workflow.autoNarrowReReviewScope',
|
|
414
|
+
]);
|
|
415
|
+
function isWorkflowKey(key) {
|
|
416
|
+
return key.startsWith('workflow.');
|
|
417
|
+
}
|
|
418
|
+
function isStateKey(key) {
|
|
419
|
+
return (key === 'activeIdea' ||
|
|
420
|
+
key === 'activeProject' ||
|
|
421
|
+
key === 'lastPausedProject');
|
|
422
|
+
}
|
|
423
|
+
function isStructuralKey(key) {
|
|
424
|
+
return (key === 'projects.root' ||
|
|
425
|
+
key === 'worktrees.root' ||
|
|
426
|
+
key === 'git.defaultBranch' ||
|
|
427
|
+
key.startsWith('documentation.') ||
|
|
428
|
+
key.startsWith('archive.') ||
|
|
429
|
+
key.startsWith('tools.'));
|
|
430
|
+
}
|
|
431
|
+
function validateSurfaceForKey(key, surface) {
|
|
432
|
+
if (surface === 'auto') {
|
|
433
|
+
return;
|
|
336
434
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
value: configRoot.replace(/\/+$/, ''),
|
|
343
|
-
source: 'config.json',
|
|
344
|
-
};
|
|
435
|
+
if (isStructuralKey(key)) {
|
|
436
|
+
if (surface !== 'shared') {
|
|
437
|
+
throw new Error(`Cannot set structural key '${key}' at '${surface}' scope. Structural keys (projects.root, worktrees.root, git.*, documentation.*, archive.*, tools.*) can only be set at shared scope (.oat/config.json).`);
|
|
438
|
+
}
|
|
439
|
+
return;
|
|
345
440
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
441
|
+
if (isStateKey(key)) {
|
|
442
|
+
// activeIdea has both a repo-local and a user-level surface in the
|
|
443
|
+
// catalog (the user-level entry is the global fallback). Both surfaces
|
|
444
|
+
// are writable; shared is not supported because an idea pointer is not
|
|
445
|
+
// a team decision.
|
|
446
|
+
if (key === 'activeIdea') {
|
|
447
|
+
if (surface !== 'local' && surface !== 'user') {
|
|
448
|
+
throw new Error(`Cannot set 'activeIdea' at '${surface}' scope. activeIdea can only be set at local scope (.oat/config.local.json) or user scope (~/.oat/config.json).`);
|
|
449
|
+
}
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
// activeProject and lastPausedProject are per-checkout state only.
|
|
453
|
+
if (surface !== 'local') {
|
|
454
|
+
throw new Error(`Cannot set state key '${key}' at '${surface}' scope. State keys (activeProject, lastPausedProject) can only be set at local scope (.oat/config.local.json).`);
|
|
455
|
+
}
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
// autoReviewAtCheckpoints is currently shared-only. Multi-surface support
|
|
459
|
+
// for behavioral keys is out of scope for p01-t04 (workflow.* keys only).
|
|
460
|
+
if (key === 'autoReviewAtCheckpoints' && surface !== 'shared') {
|
|
461
|
+
throw new Error(`Cannot set 'autoReviewAtCheckpoints' at '${surface}' scope. This key is currently shared-only.`);
|
|
462
|
+
}
|
|
463
|
+
// Workflow keys accept any non-auto surface.
|
|
352
464
|
}
|
|
353
|
-
|
|
354
|
-
if (key
|
|
355
|
-
return
|
|
465
|
+
function defaultSurfaceForKey(key) {
|
|
466
|
+
if (isWorkflowKey(key) || isStateKey(key)) {
|
|
467
|
+
return 'local';
|
|
356
468
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
else if (key === 'documentation.tooling') {
|
|
365
|
-
value = doc?.tooling ?? null;
|
|
366
|
-
}
|
|
367
|
-
else if (key === 'documentation.config') {
|
|
368
|
-
value = doc?.config ?? null;
|
|
369
|
-
}
|
|
370
|
-
else if (key === 'documentation.requireForProjectCompletion') {
|
|
371
|
-
value =
|
|
372
|
-
doc?.requireForProjectCompletion != null
|
|
373
|
-
? String(doc.requireForProjectCompletion)
|
|
374
|
-
: 'false';
|
|
469
|
+
return 'shared';
|
|
470
|
+
}
|
|
471
|
+
function parseWorkflowValue(key, rawValue) {
|
|
472
|
+
if (WORKFLOW_BOOLEAN_KEYS.has(key)) {
|
|
473
|
+
const normalized = rawValue.trim().toLowerCase();
|
|
474
|
+
if (normalized !== 'true' && normalized !== 'false') {
|
|
475
|
+
throw new Error(`Invalid value for ${key}: expected 'true' or 'false', got '${rawValue}'`);
|
|
375
476
|
}
|
|
376
|
-
return
|
|
377
|
-
key,
|
|
378
|
-
value,
|
|
379
|
-
source: doc ? 'config.json' : 'default',
|
|
380
|
-
};
|
|
477
|
+
return normalized === 'true';
|
|
381
478
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
value = archive?.s3Uri ?? null;
|
|
479
|
+
const allowed = WORKFLOW_ENUM_VALUES[key];
|
|
480
|
+
if (allowed) {
|
|
481
|
+
const normalized = rawValue.trim();
|
|
482
|
+
if (!allowed.includes(normalized)) {
|
|
483
|
+
throw new Error(`Invalid value for ${key}: expected one of ${allowed.join(' | ')}, got '${rawValue}'`);
|
|
388
484
|
}
|
|
389
|
-
|
|
390
|
-
value =
|
|
391
|
-
archive?.s3SyncOnComplete != null
|
|
392
|
-
? String(archive.s3SyncOnComplete)
|
|
393
|
-
: 'false';
|
|
394
|
-
}
|
|
395
|
-
else if (key === 'archive.summaryExportPath') {
|
|
396
|
-
value = archive?.summaryExportPath ?? null;
|
|
397
|
-
}
|
|
398
|
-
return {
|
|
399
|
-
key,
|
|
400
|
-
value,
|
|
401
|
-
source: archive ? 'config.json' : 'default',
|
|
402
|
-
};
|
|
485
|
+
return normalized;
|
|
403
486
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
487
|
+
throw new Error(`Unknown workflow key: ${key}`);
|
|
488
|
+
}
|
|
489
|
+
function applyWorkflowValue(workflow, key, value) {
|
|
490
|
+
const subKey = key.slice('workflow.'.length);
|
|
491
|
+
return {
|
|
492
|
+
...workflow,
|
|
493
|
+
[subKey]: value,
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
function formatResolvedValue(value) {
|
|
497
|
+
if (value === null || value === undefined) {
|
|
498
|
+
return null;
|
|
413
499
|
}
|
|
414
|
-
if (
|
|
415
|
-
|
|
416
|
-
return {
|
|
417
|
-
key,
|
|
418
|
-
value: config.git?.defaultBranch ?? null,
|
|
419
|
-
source: config.git?.defaultBranch ? 'config.json' : 'default',
|
|
420
|
-
};
|
|
500
|
+
if (typeof value === 'boolean') {
|
|
501
|
+
return String(value);
|
|
421
502
|
}
|
|
422
|
-
if (
|
|
423
|
-
|
|
424
|
-
if (envRoot) {
|
|
425
|
-
return {
|
|
426
|
-
key,
|
|
427
|
-
value: envRoot.replace(/\/+$/, ''),
|
|
428
|
-
source: 'env',
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
const config = await dependencies.readOatConfig(repoRoot);
|
|
432
|
-
const value = config.worktrees?.root?.trim();
|
|
433
|
-
if (value) {
|
|
434
|
-
return {
|
|
435
|
-
key,
|
|
436
|
-
value: value.replace(/\/+$/, ''),
|
|
437
|
-
source: 'config.json',
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
return {
|
|
441
|
-
key,
|
|
442
|
-
value: '.worktrees',
|
|
443
|
-
source: 'default',
|
|
444
|
-
};
|
|
503
|
+
if (typeof value === 'string') {
|
|
504
|
+
return value;
|
|
445
505
|
}
|
|
446
|
-
if (
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
506
|
+
if (Array.isArray(value)) {
|
|
507
|
+
return value.join(',');
|
|
508
|
+
}
|
|
509
|
+
return String(value);
|
|
510
|
+
}
|
|
511
|
+
async function getConfigValue(repoRoot, userConfigDir, key, dependencies) {
|
|
512
|
+
const resolved = await dependencies.resolveEffectiveConfig(repoRoot, userConfigDir, dependencies.processEnv);
|
|
513
|
+
const entry = resolved.resolved[key];
|
|
514
|
+
if (!entry) {
|
|
515
|
+
return { key, value: null, source: 'default' };
|
|
455
516
|
}
|
|
456
|
-
const localConfig = await dependencies.readOatLocalConfig(repoRoot);
|
|
457
|
-
const localKey = key;
|
|
458
|
-
const hasKey = Object.hasOwn(localConfig, localKey);
|
|
459
|
-
const value = localConfig[localKey] ?? null;
|
|
460
517
|
return {
|
|
461
518
|
key,
|
|
462
|
-
value,
|
|
463
|
-
source:
|
|
519
|
+
value: formatResolvedValue(entry.value),
|
|
520
|
+
source: entry.source,
|
|
464
521
|
};
|
|
465
522
|
}
|
|
466
|
-
async function setConfigValue(repoRoot, key, rawValue, dependencies) {
|
|
523
|
+
async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, dependencies) {
|
|
524
|
+
validateSurfaceForKey(key, surface);
|
|
525
|
+
const effectiveSurface = surface === 'auto' ? defaultSurfaceForKey(key) : surface;
|
|
526
|
+
if (isWorkflowKey(key)) {
|
|
527
|
+
const parsedValue = parseWorkflowValue(key, rawValue);
|
|
528
|
+
const displayValue = typeof parsedValue === 'boolean' ? String(parsedValue) : parsedValue;
|
|
529
|
+
if (effectiveSurface === 'user') {
|
|
530
|
+
const userConfig = await dependencies.readUserConfig(userConfigDir);
|
|
531
|
+
await dependencies.writeUserConfig(userConfigDir, {
|
|
532
|
+
...userConfig,
|
|
533
|
+
workflow: applyWorkflowValue(userConfig.workflow ?? {}, key, parsedValue),
|
|
534
|
+
});
|
|
535
|
+
return { key, value: displayValue, source: 'user' };
|
|
536
|
+
}
|
|
537
|
+
if (effectiveSurface === 'local') {
|
|
538
|
+
const localConfig = await dependencies.readOatLocalConfig(repoRoot);
|
|
539
|
+
await dependencies.writeOatLocalConfig(repoRoot, {
|
|
540
|
+
...localConfig,
|
|
541
|
+
workflow: applyWorkflowValue(localConfig.workflow ?? {}, key, parsedValue),
|
|
542
|
+
});
|
|
543
|
+
return { key, value: displayValue, source: 'local' };
|
|
544
|
+
}
|
|
545
|
+
// shared
|
|
546
|
+
const sharedConfig = await dependencies.readOatConfig(repoRoot);
|
|
547
|
+
await dependencies.writeOatConfig(repoRoot, {
|
|
548
|
+
...sharedConfig,
|
|
549
|
+
workflow: applyWorkflowValue(sharedConfig.workflow ?? {}, key, parsedValue),
|
|
550
|
+
});
|
|
551
|
+
return { key, value: displayValue, source: 'shared' };
|
|
552
|
+
}
|
|
467
553
|
if (key === 'activeIdea' ||
|
|
468
554
|
key === 'activeProject' ||
|
|
469
555
|
key === 'lastPausedProject') {
|
|
470
|
-
const localConfig = await dependencies.readOatLocalConfig(repoRoot);
|
|
471
556
|
const nextValue = rawValue === '' ? null : rawValue;
|
|
557
|
+
// activeIdea --user writes to ~/.oat/config.json
|
|
558
|
+
if (key === 'activeIdea' && effectiveSurface === 'user') {
|
|
559
|
+
const userConfig = await dependencies.readUserConfig(userConfigDir);
|
|
560
|
+
await dependencies.writeUserConfig(userConfigDir, {
|
|
561
|
+
...userConfig,
|
|
562
|
+
activeIdea: nextValue,
|
|
563
|
+
});
|
|
564
|
+
return { key, value: nextValue, source: 'user' };
|
|
565
|
+
}
|
|
566
|
+
const localConfig = await dependencies.readOatLocalConfig(repoRoot);
|
|
472
567
|
await dependencies.writeOatLocalConfig(repoRoot, {
|
|
473
568
|
...localConfig,
|
|
474
569
|
[key]: nextValue,
|
|
@@ -476,7 +571,7 @@ async function setConfigValue(repoRoot, key, rawValue, dependencies) {
|
|
|
476
571
|
return {
|
|
477
572
|
key,
|
|
478
573
|
value: nextValue,
|
|
479
|
-
source: '
|
|
574
|
+
source: 'local',
|
|
480
575
|
};
|
|
481
576
|
}
|
|
482
577
|
const config = await dependencies.readOatConfig(repoRoot);
|
|
@@ -505,7 +600,7 @@ async function setConfigValue(repoRoot, key, rawValue, dependencies) {
|
|
|
505
600
|
return {
|
|
506
601
|
key,
|
|
507
602
|
value: resultValue,
|
|
508
|
-
source: '
|
|
603
|
+
source: 'shared',
|
|
509
604
|
};
|
|
510
605
|
}
|
|
511
606
|
if (key.startsWith('archive.')) {
|
|
@@ -529,7 +624,7 @@ async function setConfigValue(repoRoot, key, rawValue, dependencies) {
|
|
|
529
624
|
return {
|
|
530
625
|
key,
|
|
531
626
|
value: resultValue,
|
|
532
|
-
source: '
|
|
627
|
+
source: 'shared',
|
|
533
628
|
};
|
|
534
629
|
}
|
|
535
630
|
if (key.startsWith('tools.')) {
|
|
@@ -543,7 +638,7 @@ async function setConfigValue(repoRoot, key, rawValue, dependencies) {
|
|
|
543
638
|
return {
|
|
544
639
|
key,
|
|
545
640
|
value: String(tools[packName] ?? false),
|
|
546
|
-
source: '
|
|
641
|
+
source: 'shared',
|
|
547
642
|
};
|
|
548
643
|
}
|
|
549
644
|
if (key === 'git.defaultBranch') {
|
|
@@ -561,7 +656,7 @@ async function setConfigValue(repoRoot, key, rawValue, dependencies) {
|
|
|
561
656
|
return {
|
|
562
657
|
key,
|
|
563
658
|
value: nextValue,
|
|
564
|
-
source: '
|
|
659
|
+
source: 'shared',
|
|
565
660
|
};
|
|
566
661
|
}
|
|
567
662
|
if (key === 'autoReviewAtCheckpoints') {
|
|
@@ -573,7 +668,7 @@ async function setConfigValue(repoRoot, key, rawValue, dependencies) {
|
|
|
573
668
|
return {
|
|
574
669
|
key,
|
|
575
670
|
value: String(nextValue),
|
|
576
|
-
source: '
|
|
671
|
+
source: 'shared',
|
|
577
672
|
};
|
|
578
673
|
}
|
|
579
674
|
const normalizedValue = normalizeSharedRoot(rawValue);
|
|
@@ -592,7 +687,7 @@ async function setConfigValue(repoRoot, key, rawValue, dependencies) {
|
|
|
592
687
|
return {
|
|
593
688
|
key,
|
|
594
689
|
value: normalizedValue,
|
|
595
|
-
source: '
|
|
690
|
+
source: 'shared',
|
|
596
691
|
};
|
|
597
692
|
}
|
|
598
693
|
function formatList(values) {
|
|
@@ -656,7 +751,8 @@ async function runGet(keyArg, context, dependencies) {
|
|
|
656
751
|
throw new Error(`Unknown config key: ${keyArg}`);
|
|
657
752
|
}
|
|
658
753
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
659
|
-
const
|
|
754
|
+
const userConfigDir = join(context.home, '.oat');
|
|
755
|
+
const value = await getConfigValue(repoRoot, userConfigDir, keyArg, dependencies);
|
|
660
756
|
if (context.json) {
|
|
661
757
|
context.logger.json({
|
|
662
758
|
status: 'ok',
|
|
@@ -679,13 +775,14 @@ async function runGet(keyArg, context, dependencies) {
|
|
|
679
775
|
process.exitCode = 1;
|
|
680
776
|
}
|
|
681
777
|
}
|
|
682
|
-
async function runSet(keyArg, rawValue, context, dependencies) {
|
|
778
|
+
async function runSet(keyArg, rawValue, surface, context, dependencies) {
|
|
683
779
|
try {
|
|
684
780
|
if (!isConfigKey(keyArg)) {
|
|
685
781
|
throw new Error(`Unknown config key: ${keyArg}`);
|
|
686
782
|
}
|
|
687
783
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
688
|
-
const
|
|
784
|
+
const userConfigDir = join(context.home, '.oat');
|
|
785
|
+
const result = await setConfigValue(repoRoot, userConfigDir, keyArg, rawValue, surface, dependencies);
|
|
689
786
|
if (context.json) {
|
|
690
787
|
context.logger.json({
|
|
691
788
|
status: 'ok',
|
|
@@ -711,9 +808,10 @@ async function runSet(keyArg, rawValue, context, dependencies) {
|
|
|
711
808
|
async function runList(context, dependencies) {
|
|
712
809
|
try {
|
|
713
810
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
811
|
+
const userConfigDir = join(context.home, '.oat');
|
|
714
812
|
const values = [];
|
|
715
813
|
for (const key of KEY_ORDER) {
|
|
716
|
-
values.push(await getConfigValue(repoRoot, key, dependencies));
|
|
814
|
+
values.push(await getConfigValue(repoRoot, userConfigDir, key, dependencies));
|
|
717
815
|
}
|
|
718
816
|
if (context.json) {
|
|
719
817
|
context.logger.json({
|
|
@@ -789,9 +887,39 @@ export function createConfigCommand(overrides = {}) {
|
|
|
789
887
|
.description('Set an OAT config value')
|
|
790
888
|
.argument('<key>', 'Config key')
|
|
791
889
|
.argument('<value>', 'Config value')
|
|
792
|
-
.
|
|
890
|
+
.option('--shared', 'Write to the shared repo config (.oat/config.json)')
|
|
891
|
+
.option('--local', 'Write to the repo-local config (.oat/config.local.json)')
|
|
892
|
+
.option('--user', 'Write to the user-level config (~/.oat/config.json)')
|
|
893
|
+
.action(async (key, value, options, command) => {
|
|
793
894
|
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
794
|
-
|
|
895
|
+
try {
|
|
896
|
+
const flagsPresent = [
|
|
897
|
+
options.shared,
|
|
898
|
+
options.local,
|
|
899
|
+
options.user,
|
|
900
|
+
].filter(Boolean).length;
|
|
901
|
+
if (flagsPresent > 1) {
|
|
902
|
+
throw new Error('--shared, --local, and --user flags are mutually exclusive; pass at most one.');
|
|
903
|
+
}
|
|
904
|
+
let surface = 'auto';
|
|
905
|
+
if (options.shared)
|
|
906
|
+
surface = 'shared';
|
|
907
|
+
else if (options.local)
|
|
908
|
+
surface = 'local';
|
|
909
|
+
else if (options.user)
|
|
910
|
+
surface = 'user';
|
|
911
|
+
await runSet(key, value, surface, context, dependencies);
|
|
912
|
+
}
|
|
913
|
+
catch (error) {
|
|
914
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
915
|
+
if (context.json) {
|
|
916
|
+
context.logger.json({ status: 'error', message });
|
|
917
|
+
}
|
|
918
|
+
else {
|
|
919
|
+
context.logger.error(message);
|
|
920
|
+
}
|
|
921
|
+
process.exitCode = 1;
|
|
922
|
+
}
|
|
795
923
|
}))
|
|
796
924
|
.addCommand(new Command('list')
|
|
797
925
|
.description('List resolved OAT config values with sources')
|
|
@@ -13,6 +13,17 @@ export interface OatArchiveConfig {
|
|
|
13
13
|
s3SyncOnComplete?: boolean;
|
|
14
14
|
summaryExportPath?: string;
|
|
15
15
|
}
|
|
16
|
+
export type WorkflowHillCheckpointDefault = 'every' | 'final';
|
|
17
|
+
export type WorkflowPostImplementSequence = 'wait' | 'summary' | 'pr' | 'docs-pr';
|
|
18
|
+
export type WorkflowReviewExecutionModel = 'subagent' | 'inline' | 'fresh-session';
|
|
19
|
+
export interface OatWorkflowConfig {
|
|
20
|
+
hillCheckpointDefault?: WorkflowHillCheckpointDefault;
|
|
21
|
+
archiveOnComplete?: boolean;
|
|
22
|
+
createPrOnComplete?: boolean;
|
|
23
|
+
postImplementSequence?: WorkflowPostImplementSequence;
|
|
24
|
+
reviewExecutionModel?: WorkflowReviewExecutionModel;
|
|
25
|
+
autoNarrowReReviewScope?: boolean;
|
|
26
|
+
}
|
|
16
27
|
export type OatToolsConfig = Partial<Record<'core' | 'ideas' | 'docs' | 'workflows' | 'utility' | 'project-management' | 'research', boolean>>;
|
|
17
28
|
export interface OatConfig {
|
|
18
29
|
version: number;
|
|
@@ -28,16 +39,19 @@ export interface OatConfig {
|
|
|
28
39
|
documentation?: OatDocumentationConfig;
|
|
29
40
|
localPaths?: string[];
|
|
30
41
|
autoReviewAtCheckpoints?: boolean;
|
|
42
|
+
workflow?: OatWorkflowConfig;
|
|
31
43
|
}
|
|
32
44
|
export interface OatLocalConfig {
|
|
33
45
|
version: number;
|
|
34
46
|
activeProject?: string | null;
|
|
35
47
|
lastPausedProject?: string | null;
|
|
36
48
|
activeIdea?: string | null;
|
|
49
|
+
workflow?: OatWorkflowConfig;
|
|
37
50
|
}
|
|
38
51
|
export interface UserConfig {
|
|
39
52
|
version: number;
|
|
40
53
|
activeIdea?: string | null;
|
|
54
|
+
workflow?: OatWorkflowConfig;
|
|
41
55
|
}
|
|
42
56
|
export interface ActiveProjectResolution {
|
|
43
57
|
name: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oat-config.d.ts","sourceRoot":"","sources":["../../src/config/oat-config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,CAClC,MAAM,CACF,MAAM,GACN,OAAO,GACP,MAAM,GACN,WAAW,GACX,SAAS,GACT,oBAAoB,GACpB,UAAU,EACZ,OAAO,CACR,CACF,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7B,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,uBAAuB,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"oat-config.d.ts","sourceRoot":"","sources":["../../src/config/oat-config.ts"],"names":[],"mappings":"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"}
|