@open-agent-toolkit/cli 0.1.37 → 0.1.39
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 +7 -3
- package/assets/docs/provider-sync/config.md +33 -0
- package/assets/docs/provider-sync/manifest-and-drift.md +6 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-review-provide/SKILL.md +2 -2
- package/assets/skills/oat-review-provide/references/review-artifact-template.md +9 -3
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +110 -6
- package/dist/commands/gate/review-verdict.d.ts +9 -1
- package/dist/commands/gate/review-verdict.d.ts.map +1 -1
- package/dist/commands/gate/review-verdict.js +153 -16
- package/dist/commands/init/index.d.ts +2 -1
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +19 -6
- package/dist/commands/status/index.d.ts +4 -0
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +25 -5
- package/dist/config/oat-config.d.ts +1 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +22 -0
- package/dist/config/sync-config.d.ts +4 -0
- package/dist/config/sync-config.d.ts.map +1 -1
- package/dist/config/sync-config.js +24 -0
- package/dist/drift/index.d.ts +2 -0
- package/dist/drift/index.d.ts.map +1 -1
- package/dist/drift/index.js +1 -0
- package/dist/drift/known-strays.d.ts +19 -0
- package/dist/drift/known-strays.d.ts.map +1 -0
- package/dist/drift/known-strays.js +37 -0
- package/package.json +2 -2
|
@@ -22,14 +22,14 @@ For the deep file-by-file reference, see:
|
|
|
22
22
|
| -------------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
|
23
23
|
| Shared repo config | `.oat/config.json` | Repo-wide non-sync settings such as `projects.root`, `git.defaultBranch`, `documentation.*`, `archive.*`, `tools.*`, and shared `workflow.*` defaults | `oat config get/set/list/describe`, `oat gate` |
|
|
24
24
|
| Repo-local config | `.oat/config.local.json` | Per-developer state for this checkout, such as `activeProject`, `lastPausedProject`, repo-local `activeIdea`, and local `workflow.*` overrides | `oat config get/set/list/describe`, `oat gate` |
|
|
25
|
-
| User config | `~/.oat/config.json` | User-level state such as global `activeIdea` fallback
|
|
26
|
-
| Provider sync config | `.oat/sync/config.json` | Provider enablement
|
|
25
|
+
| User config | `~/.oat/config.json` | User-level state such as global `activeIdea` fallback, personal `workflow.*` defaults, and personal known provider strays | `oat config describe`, `oat gate` |
|
|
26
|
+
| Provider sync config | `.oat/sync/config.json` | Provider enablement, sync strategy, and repo-level known stray settings | `oat providers set`, `oat config describe` |
|
|
27
27
|
|
|
28
28
|
The main split is:
|
|
29
29
|
|
|
30
30
|
- `.oat/config.json` for shared repo behavior
|
|
31
31
|
- `.oat/config.local.json` for local developer state
|
|
32
|
-
- `~/.oat/config.json` for user-scope fallback state
|
|
32
|
+
- `~/.oat/config.json` for user-scope fallback state and personal provider-sync exceptions
|
|
33
33
|
- `.oat/sync/config.json` for provider sync only
|
|
34
34
|
|
|
35
35
|
## The fastest way to inspect config
|
|
@@ -398,6 +398,10 @@ Use:
|
|
|
398
398
|
- `oat config describe ...` to understand sync keys
|
|
399
399
|
- `oat providers set ...` to mutate sync/provider settings
|
|
400
400
|
|
|
401
|
+
Known provider strays are the narrow cross-surface exception: repo-wide
|
|
402
|
+
`knownStrays` entries live in `.oat/sync/config.json`, while personal
|
|
403
|
+
`knownStrays` entries can live in `~/.oat/config.json`.
|
|
404
|
+
|
|
401
405
|
For the provider-sync schema details, use [Sync Config (`.oat/sync/config.json`)](../provider-sync/config.md).
|
|
402
406
|
|
|
403
407
|
## Recommended workflow
|
|
@@ -23,6 +23,7 @@ Discovery note:
|
|
|
23
23
|
It is read by:
|
|
24
24
|
|
|
25
25
|
- `oat init` (provider selection and defaults)
|
|
26
|
+
- `oat status` (known-stray suppression in drift reports and remediation)
|
|
26
27
|
- `oat sync` (active provider resolution and mismatch handling)
|
|
27
28
|
- `oat providers set` (explicit provider enable/disable updates)
|
|
28
29
|
|
|
@@ -32,6 +33,7 @@ It is read by:
|
|
|
32
33
|
{
|
|
33
34
|
"version": 1,
|
|
34
35
|
"defaultStrategy": "auto",
|
|
36
|
+
"knownStrays": [".cursor/skills/cloud-environment-setup"],
|
|
35
37
|
"providers": {
|
|
36
38
|
"claude": {
|
|
37
39
|
"enabled": true,
|
|
@@ -50,10 +52,41 @@ It is read by:
|
|
|
50
52
|
| --------------------------- | ------------------------------------- | ---------------------------------------------------------- |
|
|
51
53
|
| `version` | yes | Config schema version (currently `1`) |
|
|
52
54
|
| `defaultStrategy` | yes | Global default sync strategy: `auto`, `symlink`, or `copy` |
|
|
55
|
+
| `knownStrays` | no | Exact provider paths to suppress from stray reporting |
|
|
53
56
|
| `providers` | no (persisted), normalized at runtime | Provider-specific overrides keyed by adapter name |
|
|
54
57
|
| `providers.<name>.enabled` | no | Explicit provider activation (`true` / `false`) |
|
|
55
58
|
| `providers.<name>.strategy` | no | Per-provider strategy override (`auto`, `symlink`, `copy`) |
|
|
56
59
|
|
|
60
|
+
### Known strays
|
|
61
|
+
|
|
62
|
+
Use `knownStrays` for provider-local files that should remain unmanaged by OAT.
|
|
63
|
+
Entries are exact provider-path matches after path normalization; they are not
|
|
64
|
+
globs and do not suppress sibling paths.
|
|
65
|
+
|
|
66
|
+
Project-level config in `.oat/sync/config.json` applies to everyone using the
|
|
67
|
+
repository:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"version": 1,
|
|
72
|
+
"defaultStrategy": "auto",
|
|
73
|
+
"knownStrays": [".cursor/skills/cloud-environment-setup"]
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
User-level config in `~/.oat/config.json` is useful for personal provider-local
|
|
78
|
+
files that should not be committed to the repository:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"knownStrays": [".cursor/skills/cloud-environment-setup"]
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The common Cursor-only skill case is a good fit: the skill may intentionally
|
|
87
|
+
exist in `.cursor/skills/cloud-environment-setup` while remaining outside the
|
|
88
|
+
canonical `.agents/skills` inventory.
|
|
89
|
+
|
|
57
90
|
## Behavior notes
|
|
58
91
|
|
|
59
92
|
- If `providers.<name>.enabled` is:
|
|
@@ -53,6 +53,12 @@ Rendered rule files participate in the same drift states as other managed copies
|
|
|
53
53
|
|
|
54
54
|
Provider files ignored by Git are treated as intentionally local runtime files and are not reported as strays. This includes files covered by tracked `.gitignore`, repo-local `.git/info/exclude`, or other standard Git exclude mechanisms.
|
|
55
55
|
|
|
56
|
+
Provider files listed in sync config `knownStrays` are also omitted from stray
|
|
57
|
+
summaries and adoption prompts. Known strays can be configured at project scope
|
|
58
|
+
in `.oat/sync/config.json` or user scope in `~/.oat/config.json`; entries use
|
|
59
|
+
exact provider-path matching, so `.cursor/skills/cloud-environment-setup` does
|
|
60
|
+
not suppress `.cursor/skills/cloud-environment-setup-extra`.
|
|
61
|
+
|
|
56
62
|
For rules, adoption maps provider-native files back into `.agents/rules/*.md`:
|
|
57
63
|
|
|
58
64
|
- Claude: `.claude/rules/*.md`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oat-review-provide
|
|
3
|
-
version: 1.2.
|
|
3
|
+
version: 1.2.2
|
|
4
4
|
description: Use when you need an ad-hoc review outside an active OAT project lifecycle. Reviews code or artifacts without project phase state, unlike oat-project-review-provide.
|
|
5
5
|
argument-hint: '[unstaged|staged|base_branch=<branch>|base_sha=<sha>|<sha1>..<sha2>|--files <path1,path2,...>] [--output <path>] [--mode auto|local|tracked|inline]'
|
|
6
6
|
disable-model-invocation: true
|
|
@@ -183,7 +183,7 @@ If the file already exists (same scope reviewed twice in one day), suffix with `
|
|
|
183
183
|
|
|
184
184
|
Use the same severity model and checklist as project reviews:
|
|
185
185
|
|
|
186
|
-
- Critical / Important / Minor findings
|
|
186
|
+
- Critical / Important / Medium / Minor findings
|
|
187
187
|
- file:line references
|
|
188
188
|
- actionable fix guidance
|
|
189
189
|
- verification commands
|
|
@@ -23,19 +23,25 @@ oat_review_mode: ad_hoc
|
|
|
23
23
|
|
|
24
24
|
{2-3 sentence summary}
|
|
25
25
|
|
|
26
|
+
Findings: {N} critical, {N} important, {N} medium, {N} minor
|
|
27
|
+
|
|
26
28
|
## Findings
|
|
27
29
|
|
|
28
30
|
### Critical
|
|
29
31
|
|
|
30
|
-
{
|
|
32
|
+
{If none: "None"}
|
|
31
33
|
|
|
32
34
|
### Important
|
|
33
35
|
|
|
34
|
-
{
|
|
36
|
+
{If none: "None"}
|
|
37
|
+
|
|
38
|
+
### Medium
|
|
39
|
+
|
|
40
|
+
{If none: "None"}
|
|
35
41
|
|
|
36
42
|
### Minor
|
|
37
43
|
|
|
38
|
-
{
|
|
44
|
+
{If none: "None"}
|
|
39
45
|
|
|
40
46
|
## Verification Commands
|
|
41
47
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAO9B,OAAO,EAQL,KAAK,UAAU,EAIf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAO9B,OAAO,EAQL,KAAK,UAAU,EAIf,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,UAAU,EAEhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,UAAU,uBAAuB;IAC/B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,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;IACvE,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,KACnB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,eAAe,EAAE,CAAC,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,UAAU,EAAE,CACV,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,iBAAiB,KACvB,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AA0CD,UAAU,iBAAiB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,OAAO,EAAE,gBAAgB,GAAG,cAAc,GAAG,SAAS,CAAC;IACvD,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B;AAED,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,kBAAkB,GAAG,cAAc,GAAG,MAAM,CAAC;AAMlD,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,UAAU,CAAC;CACpB;AAyZD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,EAC9C,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,kBAAkB,GACxB,kBAAkB,GAAG,IAAI,CAE3B;AAo6BD,wBAAgB,iBAAiB,CAC/B,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,OAAO,CAwKT"}
|
|
@@ -10,7 +10,7 @@ import { resolveEffectiveConfig, resolveExecTargets, resolveGate, } from '../../
|
|
|
10
10
|
import { dirExists, fileExists } from '../../fs/io.js';
|
|
11
11
|
import { normalizeToPosixPath, resolveProjectRoot } from '../../fs/paths.js';
|
|
12
12
|
import { Command } from 'commander';
|
|
13
|
-
import { parseReviewGateVerdict, } from './review-verdict.js';
|
|
13
|
+
import { parseReviewGateVerdict, severityDisplayName, } from './review-verdict.js';
|
|
14
14
|
const DEFAULT_DEPENDENCIES = {
|
|
15
15
|
buildCommandContext,
|
|
16
16
|
resolveProjectRoot,
|
|
@@ -40,7 +40,7 @@ const VALID_REVIEW_GATE_THRESHOLDS = [
|
|
|
40
40
|
'medium',
|
|
41
41
|
'minor',
|
|
42
42
|
];
|
|
43
|
-
const REVIEW_GATE_CONTEXT_NOTE = 'This review is gate-originated. If you run `oat-project-review-provide`, set `oat_review_invocation: gate` in the review artifact.';
|
|
43
|
+
const REVIEW_GATE_CONTEXT_NOTE = 'This review is gate-originated. If you run `oat-project-review-provide`, set `oat_review_invocation: gate` in the review artifact. Write a canonical review artifact with `### Critical`, `### Important`, `### Medium`, and `### Minor` headings in that order, using `None` for empty sections.';
|
|
44
44
|
function reviewGateProjectContext(projectPath) {
|
|
45
45
|
return `Resolved OAT project path: ${projectPath}. Run the review for this project path.`;
|
|
46
46
|
}
|
|
@@ -577,15 +577,83 @@ function reviewBlocksAtThreshold(verdict, threshold) {
|
|
|
577
577
|
}
|
|
578
578
|
return verdict.counts.minor > 0;
|
|
579
579
|
}
|
|
580
|
+
function buildReviewGateHandoff(options) {
|
|
581
|
+
const receiveInstruction = `Run oat-project-review-receive for ${options.artifactPath} before treating this gate review as consumed.`;
|
|
582
|
+
const thresholdIndex = VALID_REVIEW_GATE_THRESHOLDS.indexOf(options.threshold);
|
|
583
|
+
const nonBlockingSeverities = VALID_REVIEW_GATE_THRESHOLDS.slice(thresholdIndex + 1).filter((severity) => options.verdict.counts[severity] > 0);
|
|
584
|
+
const hasFinalNonBlockingFindings = options.verdict.scope === 'final' &&
|
|
585
|
+
!options.blocking &&
|
|
586
|
+
nonBlockingSeverities.length > 0;
|
|
587
|
+
if (!hasFinalNonBlockingFindings) {
|
|
588
|
+
return receiveInstruction;
|
|
589
|
+
}
|
|
590
|
+
const counts = nonBlockingSeverities
|
|
591
|
+
.map((severity) => `${severity}=${options.verdict.counts[severity]}`)
|
|
592
|
+
.join(', ');
|
|
593
|
+
return `Gate passed at the ${options.threshold} threshold, but the final review still contains non-blocking findings (${counts}). Run oat-project-review-receive for ${options.artifactPath} to disposition them before marking the final review row passed.`;
|
|
594
|
+
}
|
|
595
|
+
function reviewGateOutcome(payload) {
|
|
596
|
+
if (payload.blocking) {
|
|
597
|
+
return 'review_completed_blocking_findings';
|
|
598
|
+
}
|
|
599
|
+
if (payload.normalization) {
|
|
600
|
+
return 'review_completed_artifact_normalized_gate_passed';
|
|
601
|
+
}
|
|
602
|
+
return 'review_completed_gate_passed';
|
|
603
|
+
}
|
|
580
604
|
function writeReviewGateResult(context, payload) {
|
|
605
|
+
const outcome = reviewGateOutcome(payload);
|
|
581
606
|
if (context.json) {
|
|
582
|
-
context.logger.json(payload);
|
|
607
|
+
context.logger.json({ outcome, ...payload });
|
|
583
608
|
return;
|
|
584
609
|
}
|
|
610
|
+
if (outcome === 'review_completed_blocking_findings') {
|
|
611
|
+
context.logger.info('Review completed and found blocking issues.');
|
|
612
|
+
}
|
|
613
|
+
else if (outcome === 'review_completed_artifact_normalized_gate_passed') {
|
|
614
|
+
context.logger.info('Review completed, artifact was normalized, and gate passed.');
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
context.logger.info('Review completed and gate passed.');
|
|
618
|
+
}
|
|
585
619
|
context.logger.info(`Review artifact: ${payload.artifactPath}`);
|
|
620
|
+
if (payload.normalization) {
|
|
621
|
+
context.logger.info(`Artifact normalized: inserted ${payload.normalization.insertedSeverities.map((severity) => severityDisplayName(severity)).join(', ')} empty Findings section(s).`);
|
|
622
|
+
}
|
|
586
623
|
context.logger.info(`Verdict: ${payload.status} (critical=${payload.counts.critical}, important=${payload.counts.important}, medium=${payload.counts.medium}, minor=${payload.counts.minor})`);
|
|
587
624
|
context.logger.info(payload.handoff);
|
|
588
625
|
}
|
|
626
|
+
function writeReviewGateExecutionFailure(context, payload) {
|
|
627
|
+
const message = `Review did not complete: target ${payload.target} exited with code ${payload.exitCode}.`;
|
|
628
|
+
if (context.json) {
|
|
629
|
+
context.logger.json({
|
|
630
|
+
status: 'review_failed',
|
|
631
|
+
outcome: 'review_did_not_complete',
|
|
632
|
+
target: payload.target,
|
|
633
|
+
project: payload.project,
|
|
634
|
+
exitCode: payload.exitCode,
|
|
635
|
+
message,
|
|
636
|
+
});
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
context.logger.error(message);
|
|
640
|
+
}
|
|
641
|
+
function writeReviewGateArtifactValidationFailure(context, payload) {
|
|
642
|
+
if (context.json) {
|
|
643
|
+
context.logger.json({
|
|
644
|
+
status: 'artifact_validation_failed',
|
|
645
|
+
outcome: 'review_completed_artifact_validation_failed',
|
|
646
|
+
target: payload.target,
|
|
647
|
+
project: payload.project,
|
|
648
|
+
artifactPath: payload.artifactPath,
|
|
649
|
+
message: payload.message,
|
|
650
|
+
recovery: payload.recovery,
|
|
651
|
+
});
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
context.logger.error(`Review completed but artifact validation failed: ${payload.message}`);
|
|
655
|
+
context.logger.error(payload.recovery);
|
|
656
|
+
}
|
|
589
657
|
async function updateConfigLayer(context, layer, dependencies, mutate) {
|
|
590
658
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
591
659
|
const userConfigDir = join(context.home, '.oat');
|
|
@@ -716,6 +784,11 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
716
784
|
]);
|
|
717
785
|
const childExitCode = await executeTarget(selected, [reviewPrompt], context, dependencies);
|
|
718
786
|
if (childExitCode !== 0) {
|
|
787
|
+
writeReviewGateExecutionFailure(context, {
|
|
788
|
+
target: selected.id,
|
|
789
|
+
project: projectPath,
|
|
790
|
+
exitCode: childExitCode,
|
|
791
|
+
});
|
|
719
792
|
process.exitCode = childExitCode;
|
|
720
793
|
return;
|
|
721
794
|
}
|
|
@@ -725,11 +798,41 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
725
798
|
});
|
|
726
799
|
const producedArtifact = findProducedReviewArtifact(before, after);
|
|
727
800
|
if (!producedArtifact) {
|
|
728
|
-
|
|
801
|
+
writeReviewGateArtifactValidationFailure(context, {
|
|
802
|
+
target: selected.id,
|
|
803
|
+
project: projectPath,
|
|
804
|
+
artifactPath: null,
|
|
805
|
+
message: `No new review artifact was detected for project ${projectPath}.`,
|
|
806
|
+
recovery: 'Ensure the review provider wrote a project review artifact. If it did, fix or attach that artifact and run oat-project-review-receive before treating the review as consumed.',
|
|
807
|
+
});
|
|
808
|
+
process.exitCode = 1;
|
|
809
|
+
return;
|
|
810
|
+
}
|
|
811
|
+
let verdict;
|
|
812
|
+
try {
|
|
813
|
+
verdict = await parseReviewGateVerdict(join(repoRoot, producedArtifact.path), {
|
|
814
|
+
normalizeMissingEmptySeveritySections: true,
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
catch (error) {
|
|
818
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
819
|
+
writeReviewGateArtifactValidationFailure(context, {
|
|
820
|
+
target: selected.id,
|
|
821
|
+
project: projectPath,
|
|
822
|
+
artifactPath: producedArtifact.path,
|
|
823
|
+
message: detail,
|
|
824
|
+
recovery: `The review artifact was created at ${producedArtifact.path} but could not be consumed. Fix the artifact format, then run oat-project-review-receive for ${producedArtifact.path}; if the only issue is a missing zero-count severity heading, rerun the gate to normalize the same artifact instead of creating a new review version.`,
|
|
825
|
+
});
|
|
826
|
+
process.exitCode = 1;
|
|
827
|
+
return;
|
|
729
828
|
}
|
|
730
|
-
const verdict = await parseReviewGateVerdict(join(repoRoot, producedArtifact.path));
|
|
731
829
|
const blocking = reviewBlocksAtThreshold(verdict, threshold);
|
|
732
|
-
const handoff =
|
|
830
|
+
const handoff = buildReviewGateHandoff({
|
|
831
|
+
artifactPath: producedArtifact.path,
|
|
832
|
+
verdict,
|
|
833
|
+
threshold,
|
|
834
|
+
blocking,
|
|
835
|
+
});
|
|
733
836
|
writeReviewGateResult(context, {
|
|
734
837
|
status: blocking ? 'blocked' : 'ok',
|
|
735
838
|
target: selected.id,
|
|
@@ -741,6 +844,7 @@ async function runReviewGate(prompt, options, context, dependencies) {
|
|
|
741
844
|
reviewType: verdict.reviewType,
|
|
742
845
|
scope: verdict.scope,
|
|
743
846
|
invocation: verdict.invocation,
|
|
847
|
+
normalization: verdict.normalization,
|
|
744
848
|
handoff,
|
|
745
849
|
});
|
|
746
850
|
process.exitCode = blocking ? 1 : 0;
|
|
@@ -10,6 +10,14 @@ export interface ReviewGateVerdict {
|
|
|
10
10
|
minor: number;
|
|
11
11
|
};
|
|
12
12
|
blocking: boolean;
|
|
13
|
+
normalization?: {
|
|
14
|
+
insertedSeverities: Severity[];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export type Severity = keyof ReviewGateVerdict['counts'];
|
|
18
|
+
export interface ParseReviewGateVerdictOptions {
|
|
19
|
+
normalizeMissingEmptySeveritySections?: boolean;
|
|
13
20
|
}
|
|
14
|
-
export declare function
|
|
21
|
+
export declare function severityDisplayName(severity: Severity): string;
|
|
22
|
+
export declare function parseReviewGateVerdict(artifactPath: string, options?: ParseReviewGateVerdictOptions): Promise<ReviewGateVerdict>;
|
|
15
23
|
//# sourceMappingURL=review-verdict.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-verdict.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/review-verdict.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC5C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,QAAQ,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"review-verdict.d.ts","sourceRoot":"","sources":["../../../src/commands/gate/review-verdict.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC5C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE;QACd,kBAAkB,EAAE,QAAQ,EAAE,CAAC;KAChC,CAAC;CACH;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAC;AAEzD,MAAM,WAAW,6BAA6B;IAC5C,qCAAqC,CAAC,EAAE,OAAO,CAAC;CACjD;AAqID,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAE9D;AAqRD,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,6BAAkC,GAC1C,OAAO,CAAC,iBAAiB,CAAC,CAsD5B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { getFrontmatterBlock } from '../shared/frontmatter.js';
|
|
3
3
|
import YAML from 'yaml';
|
|
4
4
|
const SEVERITIES = [
|
|
@@ -89,6 +89,89 @@ function normalizeHeading(value) {
|
|
|
89
89
|
}
|
|
90
90
|
return null;
|
|
91
91
|
}
|
|
92
|
+
export function severityDisplayName(severity) {
|
|
93
|
+
return severity.charAt(0).toUpperCase() + severity.slice(1);
|
|
94
|
+
}
|
|
95
|
+
function markdownLines(content) {
|
|
96
|
+
const lines = [];
|
|
97
|
+
let start = 0;
|
|
98
|
+
while (start < content.length) {
|
|
99
|
+
const newlineIndex = content.indexOf('\n', start);
|
|
100
|
+
const end = newlineIndex === -1 ? content.length : newlineIndex;
|
|
101
|
+
lines.push({
|
|
102
|
+
text: content.slice(start, end),
|
|
103
|
+
start,
|
|
104
|
+
});
|
|
105
|
+
start = newlineIndex === -1 ? content.length : newlineIndex + 1;
|
|
106
|
+
}
|
|
107
|
+
return lines;
|
|
108
|
+
}
|
|
109
|
+
function fenceMarker(line) {
|
|
110
|
+
const match = line.match(/^\s*(`{3,}|~{3,})/);
|
|
111
|
+
if (!match?.[1]) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
marker: match[1].startsWith('`') ? '`' : '~',
|
|
116
|
+
length: match[1].length,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function linesOutsideFences(content) {
|
|
120
|
+
const outsideFenceLines = [];
|
|
121
|
+
let activeFence = null;
|
|
122
|
+
for (const line of markdownLines(content)) {
|
|
123
|
+
const marker = fenceMarker(line.text);
|
|
124
|
+
if (marker) {
|
|
125
|
+
if (!activeFence) {
|
|
126
|
+
activeFence = marker;
|
|
127
|
+
}
|
|
128
|
+
else if (marker.marker === activeFence.marker &&
|
|
129
|
+
marker.length >= activeFence.length) {
|
|
130
|
+
activeFence = null;
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (!activeFence) {
|
|
135
|
+
outsideFenceLines.push(line);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return outsideFenceLines;
|
|
139
|
+
}
|
|
140
|
+
function findFindingsSection(content) {
|
|
141
|
+
const lines = linesOutsideFences(content);
|
|
142
|
+
const findingsHeading = lines.find((line) => /^##\s+Findings\s*#*\s*$/i.test(line.text));
|
|
143
|
+
if (!findingsHeading) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const start = findingsHeading.start + findingsHeading.text.length;
|
|
147
|
+
const nextPeerHeading = lines.find((line) => line.start > findingsHeading.start &&
|
|
148
|
+
/^#{1,2}\s+.+?\s*#*\s*$/.test(line.text));
|
|
149
|
+
const end = nextPeerHeading?.start ?? content.length;
|
|
150
|
+
return {
|
|
151
|
+
start,
|
|
152
|
+
end,
|
|
153
|
+
content: content.slice(start, end),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function findSeverityHeadings(content) {
|
|
157
|
+
const findingsSection = findFindingsSection(content);
|
|
158
|
+
const scanContent = findingsSection?.content ?? content;
|
|
159
|
+
const offset = findingsSection?.start ?? 0;
|
|
160
|
+
return linesOutsideFences(scanContent)
|
|
161
|
+
.map((line) => {
|
|
162
|
+
const match = line.text.match(/^#{3,6}\s+(.+?)\s*#*\s*$/);
|
|
163
|
+
return {
|
|
164
|
+
severity: normalizeHeading(match?.[1] ?? ''),
|
|
165
|
+
index: offset + line.start,
|
|
166
|
+
headingLength: line.text.length,
|
|
167
|
+
};
|
|
168
|
+
})
|
|
169
|
+
.filter((heading) => heading.severity !== null);
|
|
170
|
+
}
|
|
171
|
+
function missingSeverityHeadings(severityHeadings) {
|
|
172
|
+
const seenSeverities = new Set(severityHeadings.map((heading) => heading.severity));
|
|
173
|
+
return SEVERITIES.filter((severity) => !seenSeverities.has(severity));
|
|
174
|
+
}
|
|
92
175
|
function parseFindingsSummaryCounts(content) {
|
|
93
176
|
const match = content.match(/^Findings:\s*(\d+)\s+critical,\s*(\d+)\s+important,\s*(\d+)\s+medium,\s*(\d+)\s+minor\s*$/im);
|
|
94
177
|
if (!match) {
|
|
@@ -102,19 +185,12 @@ function parseFindingsSummaryCounts(content) {
|
|
|
102
185
|
};
|
|
103
186
|
}
|
|
104
187
|
function parseFindingsSectionCounts(content, artifactPath) {
|
|
105
|
-
const
|
|
106
|
-
const severityHeadings =
|
|
107
|
-
.map((match) => ({
|
|
108
|
-
severity: normalizeHeading(match[1] ?? ''),
|
|
109
|
-
index: match.index ?? 0,
|
|
110
|
-
headingLength: match[0].length,
|
|
111
|
-
}))
|
|
112
|
-
.filter((heading) => heading.severity !== null);
|
|
188
|
+
const findingsSection = findFindingsSection(content);
|
|
189
|
+
const severityHeadings = findSeverityHeadings(content);
|
|
113
190
|
if (severityHeadings.length === 0) {
|
|
114
191
|
return null;
|
|
115
192
|
}
|
|
116
|
-
const
|
|
117
|
-
const missingSeverities = SEVERITIES.filter((severity) => !seenSeverities.has(severity));
|
|
193
|
+
const missingSeverities = missingSeverityHeadings(severityHeadings);
|
|
118
194
|
if (missingSeverities.length > 0) {
|
|
119
195
|
throw new Error(`Review artifact at ${artifactPath} has an incomplete Findings section; expected headings for Critical, Important, Medium, and Minor. Missing: ${missingSeverities.join(', ')}.`);
|
|
120
196
|
}
|
|
@@ -127,7 +203,7 @@ function parseFindingsSectionCounts(content, artifactPath) {
|
|
|
127
203
|
for (const [offset, heading] of severityHeadings.entries()) {
|
|
128
204
|
const nextHeading = severityHeadings[offset + 1];
|
|
129
205
|
const sectionStart = heading.index + heading.headingLength;
|
|
130
|
-
const sectionEnd = nextHeading?.index ?? content.length;
|
|
206
|
+
const sectionEnd = nextHeading?.index ?? findingsSection?.end ?? content.length;
|
|
131
207
|
counts[heading.severity] = countFindingsInSection(content.slice(sectionStart, sectionEnd));
|
|
132
208
|
}
|
|
133
209
|
return counts;
|
|
@@ -150,7 +226,54 @@ function parseFrontmatterObject(frontmatter, artifactPath) {
|
|
|
150
226
|
function hasBlockingFindings(counts) {
|
|
151
227
|
return counts.critical > 0 || counts.important > 0;
|
|
152
228
|
}
|
|
153
|
-
|
|
229
|
+
function insertionTextForSeverity(severity) {
|
|
230
|
+
return `\n### ${severityDisplayName(severity)}\n\nNone\n`;
|
|
231
|
+
}
|
|
232
|
+
function insertionPointForMissingSeverity(content, missingSeverity) {
|
|
233
|
+
const findingsSection = findFindingsSection(content);
|
|
234
|
+
const sectionEnd = findingsSection?.end ?? content.length;
|
|
235
|
+
const severityHeadings = findSeverityHeadings(content);
|
|
236
|
+
const missingSeverityRank = SEVERITIES.indexOf(missingSeverity);
|
|
237
|
+
const nextHeading = severityHeadings.find((heading) => SEVERITIES.indexOf(heading.severity) > missingSeverityRank);
|
|
238
|
+
return nextHeading?.index ?? sectionEnd;
|
|
239
|
+
}
|
|
240
|
+
function insertMissingSeveritySection(content, severity) {
|
|
241
|
+
const insertionPoint = insertionPointForMissingSeverity(content, severity);
|
|
242
|
+
const insertion = insertionTextForSeverity(severity);
|
|
243
|
+
const suffix = content.slice(insertionPoint);
|
|
244
|
+
const needsTrailingBlank = suffix.length > 0 ? '\n' : '';
|
|
245
|
+
return `${content.slice(0, insertionPoint)}${insertion}${needsTrailingBlank}${suffix}`;
|
|
246
|
+
}
|
|
247
|
+
async function normalizeMissingEmptySeveritySections(artifactPath, content, counts) {
|
|
248
|
+
if (!findFindingsSection(content)) {
|
|
249
|
+
throw new Error(`Review artifact at ${artifactPath} does not contain a ## Findings section, so missing severity headings cannot be safely normalized.`);
|
|
250
|
+
}
|
|
251
|
+
let normalizedContent = content;
|
|
252
|
+
const insertedSeverities = [];
|
|
253
|
+
for (const severity of missingSeverityHeadings(findSeverityHeadings(content))) {
|
|
254
|
+
if (counts[severity] !== 0) {
|
|
255
|
+
throw new Error(`Review artifact at ${artifactPath} is missing the ${severityDisplayName(severity)} Findings section, but structured counts report ${counts[severity]} ${severity} finding(s). This cannot be safely normalized.`);
|
|
256
|
+
}
|
|
257
|
+
normalizedContent = insertMissingSeveritySection(normalizedContent, severity);
|
|
258
|
+
insertedSeverities.push(severity);
|
|
259
|
+
}
|
|
260
|
+
if (insertedSeverities.length > 0) {
|
|
261
|
+
await writeFile(artifactPath, normalizedContent, 'utf8');
|
|
262
|
+
}
|
|
263
|
+
return { content: normalizedContent, insertedSeverities };
|
|
264
|
+
}
|
|
265
|
+
function resolveCounts(content, frontmatter) {
|
|
266
|
+
const frontmatterCounts = readFrontmatterCounts(frontmatter);
|
|
267
|
+
if (frontmatterCounts) {
|
|
268
|
+
return frontmatterCounts;
|
|
269
|
+
}
|
|
270
|
+
const summaryCounts = parseFindingsSummaryCounts(content);
|
|
271
|
+
if (summaryCounts) {
|
|
272
|
+
return summaryCounts;
|
|
273
|
+
}
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
export async function parseReviewGateVerdict(artifactPath, options = {}) {
|
|
154
277
|
let content;
|
|
155
278
|
try {
|
|
156
279
|
content = await readFile(artifactPath, 'utf8');
|
|
@@ -163,9 +286,16 @@ export async function parseReviewGateVerdict(artifactPath) {
|
|
|
163
286
|
const frontmatter = frontmatterBlock
|
|
164
287
|
? parseFrontmatterObject(frontmatterBlock, artifactPath)
|
|
165
288
|
: {};
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
289
|
+
let counts = resolveCounts(content, frontmatter);
|
|
290
|
+
let insertedSeverities = [];
|
|
291
|
+
if (counts && options.normalizeMissingEmptySeveritySections) {
|
|
292
|
+
const normalized = await normalizeMissingEmptySeveritySections(artifactPath, content, counts);
|
|
293
|
+
content = normalized.content;
|
|
294
|
+
insertedSeverities = normalized.insertedSeverities;
|
|
295
|
+
}
|
|
296
|
+
if (!counts) {
|
|
297
|
+
counts = parseFindingsSectionCounts(content, artifactPath);
|
|
298
|
+
}
|
|
169
299
|
if (!counts) {
|
|
170
300
|
throw new Error(`Review artifact at ${artifactPath} does not contain recognizable review findings or explicit verdict counts.`);
|
|
171
301
|
}
|
|
@@ -176,5 +306,12 @@ export async function parseReviewGateVerdict(artifactPath) {
|
|
|
176
306
|
invocation: stringOrNull(frontmatter['oat_review_invocation']),
|
|
177
307
|
counts,
|
|
178
308
|
blocking: hasBlockingFindings(counts),
|
|
309
|
+
...(insertedSeverities.length > 0
|
|
310
|
+
? {
|
|
311
|
+
normalization: {
|
|
312
|
+
insertedSeverities,
|
|
313
|
+
},
|
|
314
|
+
}
|
|
315
|
+
: {}),
|
|
179
316
|
};
|
|
180
317
|
}
|
|
@@ -2,7 +2,7 @@ import { type CommandContext, type GlobalOptions } from '../../app/command-conte
|
|
|
2
2
|
import { type ApplyOatCoreResult } from '../init/gitignore.js';
|
|
3
3
|
import { type MultiSelectChoice, type PromptContext, type SelectChoice } from '../shared/shared.prompts.js';
|
|
4
4
|
import { type SyncConfig } from '../../config/index.js';
|
|
5
|
-
import { type OatConfig } from '../../config/oat-config.js';
|
|
5
|
+
import { type OatConfig, type UserConfig } from '../../config/oat-config.js';
|
|
6
6
|
import { type DriftReport } from '../../drift/index.js';
|
|
7
7
|
import { type CanonicalEntry, type HookInstallInfo } from '../../engine/index.js';
|
|
8
8
|
import type { Manifest } from '../../manifest/manifest.types.js';
|
|
@@ -42,6 +42,7 @@ interface InitDependencies {
|
|
|
42
42
|
uninstallHook: (projectRoot: string) => Promise<void>;
|
|
43
43
|
getAdapters: () => ProviderAdapter[];
|
|
44
44
|
loadSyncConfig: (configPath: string) => Promise<SyncConfig>;
|
|
45
|
+
readUserConfig: (userConfigDir: string) => Promise<UserConfig>;
|
|
45
46
|
saveSyncConfig: (configPath: string, config: SyncConfig) => Promise<SyncConfig>;
|
|
46
47
|
getConfigAwareAdapters: (adapters: ProviderAdapter[], scopeRoot: string, config: SyncConfig) => Promise<ConfigAwareAdaptersResult>;
|
|
47
48
|
applyOatCoreGitignore: (repoRoot: string) => Promise<ApplyOatCoreResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/init/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EAEnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,0BAA0B,CAAC;AAalC,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,YAAY,EAGlB,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/init/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,8 +12,8 @@ import { withScopeOption } from '../shared/scope-option.js';
|
|
|
12
12
|
import { confirmAction, inputWithDefault, selectManyWithAbort, selectWithAbort, } from '../shared/shared.prompts.js';
|
|
13
13
|
import { readGlobalOptions, resolveConcreteScopes, } from '../shared/shared.utils.js';
|
|
14
14
|
import { DEFAULT_SYNC_CONFIG, loadSyncConfig, saveSyncConfig, } from '../../config/index.js';
|
|
15
|
-
import { detectDefaultBranch, readOatConfig, resolveLocalPaths, writeOatConfig, } from '../../config/oat-config.js';
|
|
16
|
-
import { detectStrays } from '../../drift/index.js';
|
|
15
|
+
import { detectDefaultBranch, readUserConfig, readOatConfig, resolveLocalPaths, writeOatConfig, } from '../../config/oat-config.js';
|
|
16
|
+
import { detectStrays, filterKnownStrays, } from '../../drift/index.js';
|
|
17
17
|
import { configureLocalHooksPath, getHookInstallInfo, installHook, isHookInstalled, scanCanonical, uninstallHook, } from '../../engine/index.js';
|
|
18
18
|
import { dirExists, fileExists } from '../../fs/io.js';
|
|
19
19
|
import { resolveProjectRoot, resolveScopeRoot } from '../../fs/paths.js';
|
|
@@ -131,6 +131,7 @@ function createDependencies() {
|
|
|
131
131
|
async loadSyncConfig(configPath) {
|
|
132
132
|
return loadSyncConfig(configPath, DEFAULT_SYNC_CONFIG);
|
|
133
133
|
},
|
|
134
|
+
readUserConfig,
|
|
134
135
|
saveSyncConfig,
|
|
135
136
|
getConfigAwareAdapters,
|
|
136
137
|
applyOatCoreGitignore,
|
|
@@ -428,13 +429,16 @@ async function runInitCommand(context, dependencies, hookFlag, setupFlag) {
|
|
|
428
429
|
const scopeSummaries = [];
|
|
429
430
|
for (const scope of scopes) {
|
|
430
431
|
const scopeRoot = await dependencies.resolveScopeRoot(scope, context);
|
|
432
|
+
const syncConfigPath = join(scopeRoot, '.oat', 'sync', 'config.json');
|
|
433
|
+
const userConfigDir = join(context.home, '.oat');
|
|
434
|
+
let syncConfig = await dependencies.loadSyncConfig(syncConfigPath);
|
|
435
|
+
const userConfig = await dependencies.readUserConfig(userConfigDir);
|
|
431
436
|
let activeAdaptersForStrays;
|
|
432
437
|
if (scope === 'project') {
|
|
433
438
|
projectRoot = scopeRoot;
|
|
434
439
|
oatDirExistedBefore = await dependencies.dirExists(join(scopeRoot, '.oat'));
|
|
435
|
-
const configPath = join(scopeRoot, '.oat', 'sync', 'config.json');
|
|
436
440
|
const adapters = dependencies.getAdapters();
|
|
437
|
-
let config =
|
|
441
|
+
let config = syncConfig;
|
|
438
442
|
let resolution = await dependencies.getConfigAwareAdapters(adapters, scopeRoot, config);
|
|
439
443
|
if (!context.interactive && !context.json) {
|
|
440
444
|
context.logger.info(PROVIDER_CONFIG_REMEDIATION);
|
|
@@ -457,10 +461,11 @@ async function runInitCommand(context, dependencies, hookFlag, setupFlag) {
|
|
|
457
461
|
enabled: selectedProviderNames.has(adapter.name),
|
|
458
462
|
};
|
|
459
463
|
}
|
|
460
|
-
config = await dependencies.saveSyncConfig(
|
|
464
|
+
config = await dependencies.saveSyncConfig(syncConfigPath, {
|
|
461
465
|
...config,
|
|
462
466
|
providers,
|
|
463
467
|
});
|
|
468
|
+
syncConfig = config;
|
|
464
469
|
}
|
|
465
470
|
resolution = await dependencies.getConfigAwareAdapters(adapters, scopeRoot, config);
|
|
466
471
|
}
|
|
@@ -476,7 +481,15 @@ async function runInitCommand(context, dependencies, hookFlag, setupFlag) {
|
|
|
476
481
|
manifest = createEmptyManifest();
|
|
477
482
|
}
|
|
478
483
|
const canonicalEntries = await dependencies.scanCanonical(scopeRoot, scope);
|
|
479
|
-
const
|
|
484
|
+
const collectedStrays = await dependencies.collectStrays(scopeRoot, scope, manifest, canonicalEntries, activeAdaptersForStrays);
|
|
485
|
+
const { candidates: strays } = filterKnownStrays({
|
|
486
|
+
reports: collectedStrays.map((stray) => stray.report),
|
|
487
|
+
candidates: collectedStrays,
|
|
488
|
+
knownStrays: {
|
|
489
|
+
project: syncConfig.knownStrays,
|
|
490
|
+
user: userConfig.knownStrays,
|
|
491
|
+
},
|
|
492
|
+
});
|
|
480
493
|
let straysAdopted = 0;
|
|
481
494
|
if (!context.interactive && strays.length > 0) {
|
|
482
495
|
context.logger.warn(ADOPT_REMEDIATION);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type CommandContext, type GlobalOptions } from '../../app/command-context.js';
|
|
2
2
|
import { type CodexRoleStray } from '../shared/codex-strays.js';
|
|
3
3
|
import { type MultiSelectChoice, type PromptContext } from '../shared/shared.prompts.js';
|
|
4
|
+
import { type SyncConfig } from '../../config/index.js';
|
|
5
|
+
import { type UserConfig } from '../../config/oat-config.js';
|
|
4
6
|
import { type CopyTransform, type DriftReport } from '../../drift/index.js';
|
|
5
7
|
import { type CanonicalEntry } from '../../engine/index.js';
|
|
6
8
|
import type { Manifest } from '../../manifest/index.js';
|
|
@@ -12,6 +14,8 @@ interface StatusDependencies {
|
|
|
12
14
|
buildCommandContext: (options: GlobalOptions) => CommandContext;
|
|
13
15
|
resolveScopeRoot: (scope: ConcreteScope, context: CommandContext) => Promise<string>;
|
|
14
16
|
loadManifest: (manifestPath: string) => Promise<Manifest>;
|
|
17
|
+
loadSyncConfig: (configPath: string) => Promise<SyncConfig>;
|
|
18
|
+
readUserConfig: (userConfigDir: string) => Promise<UserConfig>;
|
|
15
19
|
saveManifest: (manifestPath: string, manifest: Manifest) => Promise<void>;
|
|
16
20
|
scanCanonical: (scopeRoot: string, scope: ConcreteScope) => Promise<CanonicalEntry[]>;
|
|
17
21
|
getAdapters: () => ProviderAdapter[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/status/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EACL,KAAK,cAAc,EAGpB,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAEnB,MAAM,iCAAiC,CAAC;AAKzC,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,WAAW,EAIjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,cAAc,EAIpB,MAAM,eAAe,CAAC;AAMvB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,uCAAuC,CAAC;AAI/C,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,KAAK,aAAa,EAGlB,KAAK,KAAK,EACX,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,UAAU,kBAAkB;IAC1B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,gBAAgB,EAAE,CAChB,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,cAAc,KACpB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1D,cAAc,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5D,cAAc,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/D,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,aAAa,EAAE,CACb,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,aAAa,KACjB,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,eAAe,EAAE,CAAC;IACrC,iBAAiB,EAAE,CACjB,QAAQ,EAAE,eAAe,EAAE,EAC3B,SAAS,EAAE,MAAM,KACd,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IAChC,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,KAAK,WAAW,EAAE,CAAC;IAC3E,WAAW,EAAE,CACX,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,EAClC,SAAS,EAAE,MAAM,EACjB,aAAa,CAAC,EAAE,aAAa,KAC1B,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1B,YAAY,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,QAAQ,EAClB,gBAAgB,EAAE,cAAc,EAAE,EAClC,OAAO,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,mBAAmB,CAAC,KAC7D,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5B,qBAAqB,EAAE,CACrB,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,cAAc,EAAE,EAClC,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,KAC3B,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC/B,gCAAgC,EAAE,CAChC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,cAAc,EAAE,KAC/B,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjC,8BAA8B,EAAE,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,kBAAkB,KACrB,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,mBAAmB,EAAE,CAAC,CAAC,SAAS,MAAM,EACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,EAC/B,GAAG,EAAE,aAAa,KACf,OAAO,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IACzB,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzE,UAAU,EAAE,CACV,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,oBAAoB,EAC3B,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE,KACrC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvB,iBAAiB,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,MAAM,CAAC;CACvD;AAED,UAAU,oBAAoB;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE;QACT,IAAI,EAAE,YAAY,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAogBD,wBAAgB,mBAAmB,CACjC,SAAS,GAAE,OAAO,CAAC,kBAAkB,CAAM,GAC1C,OAAO,CAoBT"}
|
|
@@ -5,7 +5,9 @@ import { detectCodexRoleStrays, regenerateCodexAfterAdoption, } from '../shared/
|
|
|
5
5
|
import { withScopeOption } from '../shared/scope-option.js';
|
|
6
6
|
import { confirmAction, selectManyWithAbort, } from '../shared/shared.prompts.js';
|
|
7
7
|
import { readGlobalOptions, resolveConcreteScopes, } from '../shared/shared.utils.js';
|
|
8
|
-
import {
|
|
8
|
+
import { DEFAULT_SYNC_CONFIG, loadSyncConfig, } from '../../config/index.js';
|
|
9
|
+
import { readUserConfig } from '../../config/oat-config.js';
|
|
10
|
+
import { detectDrift, detectStrays, filterKnownStrays, } from '../../drift/index.js';
|
|
9
11
|
import { HOOK_DRIFT_WARNING, HOOK_STRAY_INFO, scanCanonical, } from '../../engine/index.js';
|
|
10
12
|
import { normalizeToPosixPath, resolveProjectRoot, resolveScopeRoot, } from '../../fs/paths.js';
|
|
11
13
|
import { loadManifest, saveManifest } from '../../manifest/manager.js';
|
|
@@ -29,6 +31,10 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
29
31
|
return resolveScopeRoot(scope, context.cwd, context.home);
|
|
30
32
|
},
|
|
31
33
|
loadManifest,
|
|
34
|
+
async loadSyncConfig(configPath) {
|
|
35
|
+
return loadSyncConfig(configPath, DEFAULT_SYNC_CONFIG);
|
|
36
|
+
},
|
|
37
|
+
readUserConfig,
|
|
32
38
|
saveManifest,
|
|
33
39
|
scanCanonical,
|
|
34
40
|
getAdapters() {
|
|
@@ -113,8 +119,14 @@ function formatStrayChoiceLabel(scope, providerPath, provider) {
|
|
|
113
119
|
async function collectScopeReports(scope, context, dependencies) {
|
|
114
120
|
const scopeRoot = await dependencies.resolveScopeRoot(scope, context);
|
|
115
121
|
const manifestPath = join(scopeRoot, '.oat', 'sync', 'manifest.json');
|
|
116
|
-
const
|
|
117
|
-
const
|
|
122
|
+
const syncConfigPath = join(scopeRoot, '.oat', 'sync', 'config.json');
|
|
123
|
+
const userConfigDir = join(context.home, '.oat');
|
|
124
|
+
const [manifest, canonicalEntries, syncConfig, userConfig] = await Promise.all([
|
|
125
|
+
dependencies.loadManifest(manifestPath),
|
|
126
|
+
dependencies.scanCanonical(scopeRoot, scope),
|
|
127
|
+
dependencies.loadSyncConfig(syncConfigPath),
|
|
128
|
+
dependencies.readUserConfig(userConfigDir),
|
|
129
|
+
]);
|
|
118
130
|
const adapters = dependencies.getAdapters();
|
|
119
131
|
const activeAdapters = await dependencies.getActiveAdapters(adapters, scopeRoot);
|
|
120
132
|
const reports = [];
|
|
@@ -234,13 +246,21 @@ async function collectScopeReports(scope, context, dependencies) {
|
|
|
234
246
|
});
|
|
235
247
|
}
|
|
236
248
|
}
|
|
249
|
+
const filtered = filterKnownStrays({
|
|
250
|
+
reports,
|
|
251
|
+
candidates: strayCandidates,
|
|
252
|
+
knownStrays: {
|
|
253
|
+
project: syncConfig.knownStrays,
|
|
254
|
+
user: userConfig.knownStrays,
|
|
255
|
+
},
|
|
256
|
+
});
|
|
237
257
|
return {
|
|
238
258
|
scope,
|
|
239
259
|
scopeRoot,
|
|
240
260
|
manifestPath,
|
|
241
261
|
manifest,
|
|
242
|
-
reports,
|
|
243
|
-
strayCandidates,
|
|
262
|
+
reports: filtered.reports,
|
|
263
|
+
strayCandidates: filtered.candidates,
|
|
244
264
|
};
|
|
245
265
|
}
|
|
246
266
|
async function runStatusCommand(context, dependencies, options = {}) {
|
|
@@ -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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"}
|
|
@@ -260,6 +260,24 @@ function trimNonEmptyString(value) {
|
|
|
260
260
|
const trimmed = value.trim();
|
|
261
261
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
262
262
|
}
|
|
263
|
+
function normalizeKnownStrayPath(pathValue) {
|
|
264
|
+
const trimmed = pathValue.trim();
|
|
265
|
+
if (!trimmed) {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
const normalized = trimPathValue(normalizeToPosixPath(trimmed));
|
|
269
|
+
return normalized && normalized !== '.' ? normalized : undefined;
|
|
270
|
+
}
|
|
271
|
+
function normalizeKnownStrays(value) {
|
|
272
|
+
if (!Array.isArray(value)) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
const normalized = value
|
|
276
|
+
.filter((pathValue) => typeof pathValue === 'string')
|
|
277
|
+
.map((pathValue) => normalizeKnownStrayPath(pathValue))
|
|
278
|
+
.filter((pathValue) => pathValue !== undefined);
|
|
279
|
+
return normalized.length > 0 ? [...new Set(normalized)].sort() : undefined;
|
|
280
|
+
}
|
|
263
281
|
function normalizeProjectPath(repoRoot, pathValue) {
|
|
264
282
|
if (pathValue == null) {
|
|
265
283
|
return null;
|
|
@@ -523,6 +541,10 @@ function normalizeUserConfig(parsed) {
|
|
|
523
541
|
? parsed.activeIdea.trim()
|
|
524
542
|
: null;
|
|
525
543
|
}
|
|
544
|
+
const knownStrays = normalizeKnownStrays(parsed.knownStrays);
|
|
545
|
+
if (knownStrays) {
|
|
546
|
+
next.knownStrays = knownStrays;
|
|
547
|
+
}
|
|
526
548
|
const workflow = normalizeWorkflowConfig(parsed.workflow);
|
|
527
549
|
if (workflow) {
|
|
528
550
|
next.workflow = workflow;
|
|
@@ -12,6 +12,7 @@ declare const ProviderConfigSchema: z.ZodObject<{
|
|
|
12
12
|
export declare const SyncConfigSchema: z.ZodObject<{
|
|
13
13
|
version: z.ZodLiteral<1>;
|
|
14
14
|
defaultStrategy: z.ZodEnum<["symlink", "copy", "auto"]>;
|
|
15
|
+
knownStrays: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
15
16
|
providers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
16
17
|
strategy: z.ZodOptional<z.ZodEnum<["symlink", "copy", "auto"]>>;
|
|
17
18
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -29,6 +30,7 @@ export declare const SyncConfigSchema: z.ZodObject<{
|
|
|
29
30
|
strategy?: "symlink" | "copy" | "auto" | undefined;
|
|
30
31
|
enabled?: boolean | undefined;
|
|
31
32
|
}> | undefined;
|
|
33
|
+
knownStrays?: string[] | undefined;
|
|
32
34
|
}, {
|
|
33
35
|
version: 1;
|
|
34
36
|
defaultStrategy: "symlink" | "copy" | "auto";
|
|
@@ -36,9 +38,11 @@ export declare const SyncConfigSchema: z.ZodObject<{
|
|
|
36
38
|
strategy?: "symlink" | "copy" | "auto" | undefined;
|
|
37
39
|
enabled?: boolean | undefined;
|
|
38
40
|
}> | undefined;
|
|
41
|
+
knownStrays?: string[] | undefined;
|
|
39
42
|
}>;
|
|
40
43
|
export type ProviderSyncConfig = z.infer<typeof ProviderConfigSchema>;
|
|
41
44
|
export type SyncConfig = z.infer<typeof SyncConfigSchema> & {
|
|
45
|
+
knownStrays: string[];
|
|
42
46
|
providers: Record<string, ProviderSyncConfig>;
|
|
43
47
|
};
|
|
44
48
|
export declare const DEFAULT_SYNC_CONFIG: SyncConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-config.d.ts","sourceRoot":"","sources":["../../src/config/sync-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sync-config.d.ts","sourceRoot":"","sources":["../../src/config/sync-config.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,QAAA,MAAM,oBAAoB;;;;;;;;;EAGxB,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAK3B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEtE,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,GAAG;IAC1D,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAC/C,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,UAKjC,CAAC;AA6EF,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,QAAQ,GAAE,UAAgC,GACzC,OAAO,CAAC,UAAU,CAAC,CA6BrB;AAED,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,UAAU,CAAC,CAcrB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { CliError } from '../errors/index.js';
|
|
3
3
|
import { atomicWriteJson } from '../fs/io.js';
|
|
4
|
+
import { normalizeToPosixPath } from '../fs/paths.js';
|
|
4
5
|
import { SyncStrategySchema } from '../shared/types.js';
|
|
5
6
|
import { z } from 'zod';
|
|
6
7
|
import { parseJsonConfig } from './json.js';
|
|
@@ -11,11 +12,13 @@ const ProviderConfigSchema = z.object({
|
|
|
11
12
|
export const SyncConfigSchema = z.object({
|
|
12
13
|
version: z.literal(1),
|
|
13
14
|
defaultStrategy: SyncStrategySchema,
|
|
15
|
+
knownStrays: z.array(z.string()).optional(),
|
|
14
16
|
providers: z.record(ProviderConfigSchema).optional(),
|
|
15
17
|
});
|
|
16
18
|
export const DEFAULT_SYNC_CONFIG = {
|
|
17
19
|
version: 1,
|
|
18
20
|
defaultStrategy: 'auto',
|
|
21
|
+
knownStrays: [],
|
|
19
22
|
providers: {},
|
|
20
23
|
};
|
|
21
24
|
function mergeProviderConfigs(base, override) {
|
|
@@ -28,10 +31,30 @@ function mergeProviderConfigs(base, override) {
|
|
|
28
31
|
}
|
|
29
32
|
return merged;
|
|
30
33
|
}
|
|
34
|
+
function normalizeKnownStrayPath(pathValue) {
|
|
35
|
+
const trimmed = pathValue.trim();
|
|
36
|
+
if (!trimmed) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
const normalized = normalizeToPosixPath(trimmed)
|
|
40
|
+
.replace(/\/+$/, '')
|
|
41
|
+
.replace(/^\.\//, '');
|
|
42
|
+
return normalized && normalized !== '.' ? normalized : undefined;
|
|
43
|
+
}
|
|
44
|
+
function normalizeKnownStrays(paths) {
|
|
45
|
+
const normalized = paths
|
|
46
|
+
?.map((pathValue) => normalizeKnownStrayPath(pathValue))
|
|
47
|
+
.filter((pathValue) => pathValue !== undefined);
|
|
48
|
+
return [...new Set(normalized ?? [])].sort();
|
|
49
|
+
}
|
|
31
50
|
function normalizeConfig(config, defaults) {
|
|
32
51
|
return {
|
|
33
52
|
version: 1,
|
|
34
53
|
defaultStrategy: config.defaultStrategy ?? defaults.defaultStrategy,
|
|
54
|
+
knownStrays: normalizeKnownStrays([
|
|
55
|
+
...defaults.knownStrays,
|
|
56
|
+
...(config.knownStrays ?? []),
|
|
57
|
+
]),
|
|
35
58
|
providers: mergeProviderConfigs(defaults.providers, config.providers ?? {}),
|
|
36
59
|
};
|
|
37
60
|
}
|
|
@@ -61,6 +84,7 @@ export async function loadSyncConfig(configPath, defaults = DEFAULT_SYNC_CONFIG)
|
|
|
61
84
|
error.code === 'ENOENT') {
|
|
62
85
|
return {
|
|
63
86
|
...defaults,
|
|
87
|
+
knownStrays: [...defaults.knownStrays],
|
|
64
88
|
providers: { ...defaults.providers },
|
|
65
89
|
};
|
|
66
90
|
}
|
package/dist/drift/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { detectDrift } from './detector.js';
|
|
2
2
|
export type { CopyTransform } from './detector.js';
|
|
3
3
|
export type { DriftReport, DriftState } from './drift.types.js';
|
|
4
|
+
export { filterKnownStrays } from './known-strays.js';
|
|
5
|
+
export type { FilterKnownStraysOptions, FilterKnownStraysResult, KnownStrayCandidate, KnownStraySources, } from './known-strays.js';
|
|
4
6
|
export { detectStrays } from './strays.js';
|
|
5
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/drift/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/drift/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EACV,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/drift/index.js
CHANGED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DriftReport } from './drift.types.js';
|
|
2
|
+
export interface KnownStraySources {
|
|
3
|
+
project?: readonly string[];
|
|
4
|
+
user?: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
export interface KnownStrayCandidate {
|
|
7
|
+
report: DriftReport;
|
|
8
|
+
}
|
|
9
|
+
export interface FilterKnownStraysOptions<Candidate extends KnownStrayCandidate> {
|
|
10
|
+
reports: readonly DriftReport[];
|
|
11
|
+
candidates: readonly Candidate[];
|
|
12
|
+
knownStrays?: KnownStraySources;
|
|
13
|
+
}
|
|
14
|
+
export interface FilterKnownStraysResult<Candidate extends KnownStrayCandidate> {
|
|
15
|
+
reports: DriftReport[];
|
|
16
|
+
candidates: Candidate[];
|
|
17
|
+
}
|
|
18
|
+
export declare function filterKnownStrays<Candidate extends KnownStrayCandidate>(options: FilterKnownStraysOptions<Candidate>): FilterKnownStraysResult<Candidate>;
|
|
19
|
+
//# sourceMappingURL=known-strays.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"known-strays.d.ts","sourceRoot":"","sources":["../../src/drift/known-strays.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB,CACvC,SAAS,SAAS,mBAAmB;IAErC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IAChC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;IACjC,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC;AAED,MAAM,WAAW,uBAAuB,CACtC,SAAS,SAAS,mBAAmB;IAErC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,UAAU,EAAE,SAAS,EAAE,CAAC;CACzB;AAuCD,wBAAgB,iBAAiB,CAAC,SAAS,SAAS,mBAAmB,EACrE,OAAO,EAAE,wBAAwB,CAAC,SAAS,CAAC,GAC3C,uBAAuB,CAAC,SAAS,CAAC,CAiBpC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { normalizeToPosixPath } from '../fs/paths.js';
|
|
2
|
+
function normalizeProviderPath(pathValue) {
|
|
3
|
+
const trimmed = pathValue.trim();
|
|
4
|
+
if (!trimmed) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
const normalized = normalizeToPosixPath(trimmed)
|
|
8
|
+
.replace(/\/+$/, '')
|
|
9
|
+
.replace(/^\.\//, '');
|
|
10
|
+
return normalized && normalized !== '.' ? normalized : undefined;
|
|
11
|
+
}
|
|
12
|
+
function resolveKnownStrayPaths(knownStrays) {
|
|
13
|
+
const paths = [...(knownStrays?.project ?? []), ...(knownStrays?.user ?? [])];
|
|
14
|
+
return new Set(paths
|
|
15
|
+
.map((pathValue) => normalizeProviderPath(pathValue))
|
|
16
|
+
.filter((pathValue) => pathValue !== undefined));
|
|
17
|
+
}
|
|
18
|
+
function isKnownStrayReport(report, knownStrayPaths) {
|
|
19
|
+
if (report.state.status !== 'stray') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const providerPath = normalizeProviderPath(report.providerPath);
|
|
23
|
+
return providerPath !== undefined && knownStrayPaths.has(providerPath);
|
|
24
|
+
}
|
|
25
|
+
export function filterKnownStrays(options) {
|
|
26
|
+
const knownStrayPaths = resolveKnownStrayPaths(options.knownStrays);
|
|
27
|
+
if (knownStrayPaths.size === 0) {
|
|
28
|
+
return {
|
|
29
|
+
reports: [...options.reports],
|
|
30
|
+
candidates: [...options.candidates],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
reports: options.reports.filter((report) => !isKnownStrayReport(report, knownStrayPaths)),
|
|
35
|
+
candidates: options.candidates.filter((candidate) => !isKnownStrayReport(candidate.report, knownStrayPaths)),
|
|
36
|
+
};
|
|
37
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-agent-toolkit/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
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.
|
|
37
|
+
"@open-agent-toolkit/control-plane": "0.1.39"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.10.0",
|