@open-agent-toolkit/cli 0.2.65 → 0.2.67
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/bundle-metadata.json +1 -1
- package/assets/docs/cli-utilities/configuration.md +33 -2
- package/assets/docs/cli-utilities/index.md +3 -0
- package/assets/docs/cli-utilities/project-log.md +63 -4
- package/assets/docs/cli-utilities/remote-project-management.md +191 -0
- package/assets/docs/contributing/code.md +8 -4
- package/assets/docs/contributing/skills.md +29 -17
- package/assets/docs/docs-tooling/commands.md +3 -1
- package/assets/docs/provider-sync/manifest-and-drift.md +2 -18
- package/assets/docs/reference/cli-reference.md +12 -1
- package/assets/docs/reference/file-locations.md +22 -0
- package/assets/docs/reference/oat-directory-structure.md +30 -17
- package/assets/docs/reference/troubleshooting.md +44 -0
- package/assets/docs/workflows/projects/lifecycle.md +17 -0
- package/assets/docs/workflows/projects/picking-up-projects.md +18 -0
- package/assets/docs/workflows/skills/index.md +33 -0
- package/assets/docs/workflows/skills/repo-improve.md +7 -3
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/create-agnostic-skill/SKILL.md +19 -37
- package/assets/skills/create-agnostic-skill/references/docs/skills-guide.md +58 -15
- package/assets/skills/create-agnostic-skill/references/skill-template.md +17 -15
- package/assets/skills/oat-agent-instructions-apply/SKILL.md +1 -1
- package/assets/skills/oat-agent-instructions-apply/references/instruction-file-templates/glob-scoped-rule.md +1 -4
- package/assets/skills/oat-doctor/SKILL.md +3 -6
- package/assets/skills/oat-pjm-remote/SKILL.md +101 -0
- package/assets/skills/oat-pjm-remote/references/external-action-protocol.md +43 -0
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
- package/assets/skills/oat-project-complete/SKILL.md +158 -30
- package/assets/skills/oat-project-complete/scripts/finalize-synced-archive.mjs +26 -7
- package/assets/skills/oat-project-complete/scripts/validate-durable-archive-receipt.mjs +183 -0
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-retro/SKILL.md +1 -1
- package/assets/skills/oat-project-retro/references/apply-procedure.md +11 -0
- package/assets/skills/oat-project-review-provide/SKILL.md +4 -4
- package/assets/skills/oat-project-summary/SKILL.md +24 -2
- package/assets/skills/oat-repo-improve/SKILL.md +9 -2
- package/assets/skills/oat-repo-improve/references/plan-template.md +4 -6
- package/assets/skills/oat-repo-knowledge-index/SKILL.md +11 -9
- package/assets/skills/oat-wave-execute/SKILL.md +20 -6
- package/assets/skills/oat-wave-program/SKILL.md +9 -4
- package/dist/commands/backlog/new.d.ts +1 -0
- package/dist/commands/backlog/new.d.ts.map +1 -1
- package/dist/commands/backlog/new.js +3 -1
- package/dist/commands/config/index.d.ts +3 -1
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +362 -36
- package/dist/commands/docs/index-generate/index.d.ts.map +1 -1
- package/dist/commands/docs/index-generate/index.js +68 -12
- package/dist/commands/docs/init/index.d.ts +11 -0
- package/dist/commands/docs/init/index.d.ts.map +1 -1
- package/dist/commands/docs/init/index.js +19 -1
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +10 -2
- package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
- package/dist/commands/instructions/instructions.utils.js +42 -9
- package/dist/commands/internal/validate-skill-version-bumps.d.ts.map +1 -1
- package/dist/commands/internal/validate-skill-version-bumps.js +5 -5
- package/dist/commands/pjm/doctor.d.ts +2 -0
- package/dist/commands/pjm/doctor.d.ts.map +1 -1
- package/dist/commands/pjm/doctor.js +71 -1
- package/dist/commands/pjm/index.d.ts +2 -0
- package/dist/commands/pjm/index.d.ts.map +1 -1
- package/dist/commands/pjm/index.js +3 -0
- package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts +60 -0
- package/dist/commands/pjm/remote/__integration__/lifecycle-harness.d.ts.map +1 -0
- package/dist/commands/pjm/remote/__integration__/lifecycle-harness.js +151 -0
- package/dist/commands/pjm/remote/association.d.ts +27 -0
- package/dist/commands/pjm/remote/association.d.ts.map +1 -0
- package/dist/commands/pjm/remote/association.js +68 -0
- package/dist/commands/pjm/remote/authority.d.ts +210 -0
- package/dist/commands/pjm/remote/authority.d.ts.map +1 -0
- package/dist/commands/pjm/remote/authority.js +341 -0
- package/dist/commands/pjm/remote/batch.d.ts +15 -0
- package/dist/commands/pjm/remote/batch.d.ts.map +1 -0
- package/dist/commands/pjm/remote/batch.js +126 -0
- package/dist/commands/pjm/remote/closeout.d.ts +69 -0
- package/dist/commands/pjm/remote/closeout.d.ts.map +1 -0
- package/dist/commands/pjm/remote/closeout.js +208 -0
- package/dist/commands/pjm/remote/create-binding.d.ts +62 -0
- package/dist/commands/pjm/remote/create-binding.d.ts.map +1 -0
- package/dist/commands/pjm/remote/create-binding.js +126 -0
- package/dist/commands/pjm/remote/credential-safety.d.ts +7 -0
- package/dist/commands/pjm/remote/credential-safety.d.ts.map +1 -0
- package/dist/commands/pjm/remote/credential-safety.js +21 -0
- package/dist/commands/pjm/remote/discussion.d.ts +49 -0
- package/dist/commands/pjm/remote/discussion.d.ts.map +1 -0
- package/dist/commands/pjm/remote/discussion.js +124 -0
- package/dist/commands/pjm/remote/doctor.d.ts +22 -0
- package/dist/commands/pjm/remote/doctor.d.ts.map +1 -0
- package/dist/commands/pjm/remote/doctor.js +380 -0
- package/dist/commands/pjm/remote/external-action.d.ts +208 -0
- package/dist/commands/pjm/remote/external-action.d.ts.map +1 -0
- package/dist/commands/pjm/remote/external-action.js +367 -0
- package/dist/commands/pjm/remote/host-execution.d.ts +28 -0
- package/dist/commands/pjm/remote/host-execution.d.ts.map +1 -0
- package/dist/commands/pjm/remote/host-execution.js +63 -0
- package/dist/commands/pjm/remote/index.d.ts +41 -0
- package/dist/commands/pjm/remote/index.d.ts.map +1 -0
- package/dist/commands/pjm/remote/index.js +280 -0
- package/dist/commands/pjm/remote/jira-adf.d.ts +35 -0
- package/dist/commands/pjm/remote/jira-adf.d.ts.map +1 -0
- package/dist/commands/pjm/remote/jira-adf.js +169 -0
- package/dist/commands/pjm/remote/lifecycle.d.ts +163 -0
- package/dist/commands/pjm/remote/lifecycle.d.ts.map +1 -0
- package/dist/commands/pjm/remote/lifecycle.js +224 -0
- package/dist/commands/pjm/remote/local-projection.d.ts +30 -0
- package/dist/commands/pjm/remote/local-projection.d.ts.map +1 -0
- package/dist/commands/pjm/remote/local-projection.js +95 -0
- package/dist/commands/pjm/remote/managed-markdown.d.ts +30 -0
- package/dist/commands/pjm/remote/managed-markdown.d.ts.map +1 -0
- package/dist/commands/pjm/remote/managed-markdown.js +128 -0
- package/dist/commands/pjm/remote/migrate.d.ts +14 -0
- package/dist/commands/pjm/remote/migrate.d.ts.map +1 -0
- package/dist/commands/pjm/remote/migrate.js +32 -0
- package/dist/commands/pjm/remote/operation-state.d.ts +15 -0
- package/dist/commands/pjm/remote/operation-state.d.ts.map +1 -0
- package/dist/commands/pjm/remote/operation-state.js +143 -0
- package/dist/commands/pjm/remote/outbound-projection-safety.d.ts +25 -0
- package/dist/commands/pjm/remote/outbound-projection-safety.d.ts.map +1 -0
- package/dist/commands/pjm/remote/outbound-projection-safety.js +99 -0
- package/dist/commands/pjm/remote/output.d.ts +60 -0
- package/dist/commands/pjm/remote/output.d.ts.map +1 -0
- package/dist/commands/pjm/remote/output.js +48 -0
- package/dist/commands/pjm/remote/preview.d.ts +88 -0
- package/dist/commands/pjm/remote/preview.d.ts.map +1 -0
- package/dist/commands/pjm/remote/preview.js +154 -0
- package/dist/commands/pjm/remote/provider-conformance.d.ts +13 -0
- package/dist/commands/pjm/remote/provider-conformance.d.ts.map +1 -0
- package/dist/commands/pjm/remote/provider-conformance.js +37 -0
- package/dist/commands/pjm/remote/provider.d.ts +57 -0
- package/dist/commands/pjm/remote/provider.d.ts.map +1 -0
- package/dist/commands/pjm/remote/provider.js +28 -0
- package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts +46 -0
- package/dist/commands/pjm/remote/providers/github-publication-safety.d.ts.map +1 -0
- package/dist/commands/pjm/remote/providers/github-publication-safety.js +126 -0
- package/dist/commands/pjm/remote/providers/github.d.ts +207 -0
- package/dist/commands/pjm/remote/providers/github.d.ts.map +1 -0
- package/dist/commands/pjm/remote/providers/github.js +1456 -0
- package/dist/commands/pjm/remote/providers/jira.d.ts +245 -0
- package/dist/commands/pjm/remote/providers/jira.d.ts.map +1 -0
- package/dist/commands/pjm/remote/providers/jira.js +1650 -0
- package/dist/commands/pjm/remote/providers/linear.d.ts +182 -0
- package/dist/commands/pjm/remote/providers/linear.d.ts.map +1 -0
- package/dist/commands/pjm/remote/providers/linear.js +1289 -0
- package/dist/commands/pjm/remote/purpose-policy.d.ts +29 -0
- package/dist/commands/pjm/remote/purpose-policy.d.ts.map +1 -0
- package/dist/commands/pjm/remote/purpose-policy.js +118 -0
- package/dist/commands/pjm/remote/reconcile.d.ts +42 -0
- package/dist/commands/pjm/remote/reconcile.d.ts.map +1 -0
- package/dist/commands/pjm/remote/reconcile.js +101 -0
- package/dist/commands/pjm/remote/resolution.d.ts +122 -0
- package/dist/commands/pjm/remote/resolution.d.ts.map +1 -0
- package/dist/commands/pjm/remote/resolution.js +243 -0
- package/dist/commands/pjm/remote/schema.d.ts +9309 -0
- package/dist/commands/pjm/remote/schema.d.ts.map +1 -0
- package/dist/commands/pjm/remote/schema.js +1503 -0
- package/dist/commands/pjm/remote/service.d.ts +20 -0
- package/dist/commands/pjm/remote/service.d.ts.map +1 -0
- package/dist/commands/pjm/remote/service.js +5121 -0
- package/dist/commands/pjm/remote/shared-storage.d.ts +36 -0
- package/dist/commands/pjm/remote/shared-storage.d.ts.map +1 -0
- package/dist/commands/pjm/remote/shared-storage.js +110 -0
- package/dist/commands/pjm/remote/snapshot.d.ts +32 -0
- package/dist/commands/pjm/remote/snapshot.d.ts.map +1 -0
- package/dist/commands/pjm/remote/snapshot.js +140 -0
- package/dist/commands/pjm/remote/storage-locator.d.ts +29 -0
- package/dist/commands/pjm/remote/storage-locator.d.ts.map +1 -0
- package/dist/commands/pjm/remote/storage-locator.js +62 -0
- package/dist/commands/pjm/remote/store.d.ts +85 -0
- package/dist/commands/pjm/remote/store.d.ts.map +1 -0
- package/dist/commands/pjm/remote/store.js +553 -0
- package/dist/commands/pjm/remote/verification.d.ts +40 -0
- package/dist/commands/pjm/remote/verification.d.ts.map +1 -0
- package/dist/commands/pjm/remote/verification.js +100 -0
- package/dist/commands/project/dispatch-ceiling/index.d.ts.map +1 -1
- package/dist/commands/project/dispatch-ceiling/index.js +32 -18
- package/dist/commands/project/log/append.d.ts +48 -0
- package/dist/commands/project/log/append.d.ts.map +1 -1
- package/dist/commands/project/log/append.js +207 -30
- package/dist/commands/project/log/check.d.ts +87 -1
- package/dist/commands/project/log/check.d.ts.map +1 -1
- package/dist/commands/project/log/check.js +139 -5
- package/dist/commands/project/log/grammar.d.ts +165 -0
- package/dist/commands/project/log/grammar.d.ts.map +1 -1
- package/dist/commands/project/log/grammar.js +219 -1
- package/dist/commands/project/log/rollup.d.ts +16 -1
- package/dist/commands/project/log/rollup.d.ts.map +1 -1
- package/dist/commands/project/log/rollup.js +22 -2
- package/dist/commands/project/log/synthesize.d.ts +16 -0
- package/dist/commands/project/log/synthesize.d.ts.map +1 -1
- package/dist/commands/project/log/synthesize.js +85 -9
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +24 -2
- package/dist/commands/sync/apply.d.ts.map +1 -1
- package/dist/commands/sync/apply.js +6 -4
- package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-manifest.js +1 -0
- package/dist/config/dispatch-matrix.d.ts.map +1 -1
- package/dist/config/dispatch-matrix.js +13 -5
- package/dist/config/oat-config.d.ts +41 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +247 -9
- package/dist/config/own-keys.d.ts +22 -0
- package/dist/config/own-keys.d.ts.map +1 -0
- package/dist/config/own-keys.js +32 -0
- package/dist/config/resolve.d.ts +11 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +35 -11
- package/dist/config/sync-config.d.ts.map +1 -1
- package/dist/config/sync-config.js +16 -0
- package/dist/drift/detector.d.ts.map +1 -1
- package/dist/drift/detector.js +52 -1
- package/dist/drift/skill-view-diagnostic.d.ts.map +1 -1
- package/dist/drift/skill-view-diagnostic.js +2 -23
- package/dist/engine/compute-plan.d.ts.map +1 -1
- package/dist/engine/compute-plan.js +22 -72
- package/dist/engine/managed-copy-hash.d.ts +69 -0
- package/dist/engine/managed-copy-hash.d.ts.map +1 -0
- package/dist/engine/managed-copy-hash.js +175 -0
- package/dist/fs/assets.d.ts +11 -0
- package/dist/fs/assets.d.ts.map +1 -1
- package/dist/fs/assets.js +1 -1
- package/dist/manifest/hash.d.ts +110 -0
- package/dist/manifest/hash.d.ts.map +1 -1
- package/dist/manifest/hash.js +111 -13
- package/dist/providers/ceiling/registry.d.ts.map +1 -1
- package/dist/providers/ceiling/registry.js +6 -1
- package/dist/providers/identity/dispatch-report.d.ts.map +1 -1
- package/dist/providers/identity/dispatch-report.js +4 -1
- package/dist/release/public-package-contract.d.ts.map +1 -1
- package/dist/release/public-package-contract.js +21 -0
- package/dist/validation/skills.d.ts.map +1 -1
- package/dist/validation/skills.js +305 -40
- package/package.json +2 -2
|
@@ -11,9 +11,11 @@ import { normalizeDispatchMatrix, validateDispatchRouteTarget, walkDispatchMatri
|
|
|
11
11
|
import { formatDispatchNotices, terminalReviewerNoticesForMatrix, } from '../../config/dispatch-notices.js';
|
|
12
12
|
import { dispatchPolicyModeDescription, dispatchPolicyPolicyDescription, managedDispatchPolicyValueList, } from '../../config/dispatch-policy-options.js';
|
|
13
13
|
import { parseJsonConfig } from '../../config/json.js';
|
|
14
|
-
import { VALID_DISPATCH_POLICY_MODES, VALID_MANAGED_DISPATCH_POLICIES, MAX_GATE_TIMEOUT_MS, MIN_GATE_TIMEOUT_MS, isValidGateTimeoutMs, normalizeWorkflowPostImplementSequence, readOatConfig, readOatConfigForDefaultScopeRepair, readOatConfigForDocumentationExcludesRepair, readOatConfigForInstructionPointerExcludesRepair, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, } from '../../config/oat-config.js';
|
|
15
|
-
import {
|
|
14
|
+
import { VALID_DISPATCH_POLICY_MODES, VALID_MANAGED_DISPATCH_POLICIES, MAX_GATE_TIMEOUT_MS, MIN_GATE_TIMEOUT_MS, isValidGateTimeoutMs, normalizeWorkflowPostImplementSequence, readOatConfig, readOatConfigForDefaultScopeRepair, readOatConfigForDocumentationExcludesRepair, readOatConfigForInstructionPointerExcludesRepair, readOatConfigWithWarnings, readOatLocalConfig, readUserConfig, writeOatConfig, writeOatLocalConfig, writeUserConfig, } from '../../config/oat-config.js';
|
|
15
|
+
import { getOwnKey, setOwnKey } from '../../config/own-keys.js';
|
|
16
|
+
import { resolveEffectiveConfig, resolveEnvOverride, } from '../../config/resolve.js';
|
|
16
17
|
import { resolveAssetsRoot } from '../../fs/assets.js';
|
|
18
|
+
import { atomicWriteJson } from '../../fs/io.js';
|
|
17
19
|
import { resolveProjectRoot } from '../../fs/paths.js';
|
|
18
20
|
import { normalizeMatrixCellAvailability, validateMatrixCell, } from '../../providers/identity/availability.js';
|
|
19
21
|
import { createDispatchValidationPassContext, validateDispatchMatrixRefs, } from '../../providers/identity/dispatch-validation.js';
|
|
@@ -28,6 +30,31 @@ const DISPATCH_MATRIX_TIERS = [
|
|
|
28
30
|
'high',
|
|
29
31
|
'frontier',
|
|
30
32
|
];
|
|
33
|
+
const PJM_REMOTE_PROVIDERS = ['github', 'linear', 'jira'];
|
|
34
|
+
const PJM_REMOTE_OPERATIONS = [
|
|
35
|
+
'create',
|
|
36
|
+
'update-fields',
|
|
37
|
+
'transition',
|
|
38
|
+
'annotate',
|
|
39
|
+
'delete',
|
|
40
|
+
'relink',
|
|
41
|
+
'detach',
|
|
42
|
+
'recreate',
|
|
43
|
+
];
|
|
44
|
+
const PJM_REMOTE_CONFIG_KEYS = [
|
|
45
|
+
'pjm.remote',
|
|
46
|
+
'pjm.remote.schemaVersion',
|
|
47
|
+
'pjm.remote.storage.state',
|
|
48
|
+
'pjm.remote.policy',
|
|
49
|
+
'pjm.remote.policy.description',
|
|
50
|
+
'pjm.remote.policy.authority.default',
|
|
51
|
+
...PJM_REMOTE_OPERATIONS.map((operation) => `pjm.remote.policy.authority.operations.${operation}`),
|
|
52
|
+
...PJM_REMOTE_PROVIDERS.flatMap((provider) => [
|
|
53
|
+
`pjm.remote.policy.providers.${provider}.description`,
|
|
54
|
+
`pjm.remote.policy.providers.${provider}.authority.default`,
|
|
55
|
+
...PJM_REMOTE_OPERATIONS.map((operation) => `pjm.remote.policy.providers.${provider}.authority.operations.${operation}`),
|
|
56
|
+
]),
|
|
57
|
+
];
|
|
31
58
|
const KEY_ORDER = [
|
|
32
59
|
'activeIdea',
|
|
33
60
|
'activeProject',
|
|
@@ -58,6 +85,7 @@ const KEY_ORDER = [
|
|
|
58
85
|
'git.defaultBranch',
|
|
59
86
|
'projects.root',
|
|
60
87
|
'projects.defaultScope',
|
|
88
|
+
...PJM_REMOTE_CONFIG_KEYS,
|
|
61
89
|
'tools.brainstorm',
|
|
62
90
|
'tools.core',
|
|
63
91
|
'tools.docs',
|
|
@@ -94,7 +122,45 @@ const KEY_ORDER = [
|
|
|
94
122
|
'workflow.gateTimeouts.artifact',
|
|
95
123
|
'worktrees.root',
|
|
96
124
|
];
|
|
125
|
+
const PJM_REMOTE_CONFIG_CATALOG = PJM_REMOTE_CONFIG_KEYS.map((key) => {
|
|
126
|
+
const aggregate = key === 'pjm.remote' || key === 'pjm.remote.policy';
|
|
127
|
+
const schemaVersion = key === 'pjm.remote.schemaVersion';
|
|
128
|
+
const storage = key === 'pjm.remote.storage.state';
|
|
129
|
+
const authority = key.includes('.authority.');
|
|
130
|
+
const description = key.endsWith('.description');
|
|
131
|
+
const type = schemaVersion
|
|
132
|
+
? 'literal 1'
|
|
133
|
+
: storage
|
|
134
|
+
? 'local | shared'
|
|
135
|
+
: authority
|
|
136
|
+
? 'read-only | user-approved | user-authorized | autonomous'
|
|
137
|
+
: description
|
|
138
|
+
? 'none | managed-section | replace'
|
|
139
|
+
: 'object';
|
|
140
|
+
return {
|
|
141
|
+
key,
|
|
142
|
+
group: 'PJM Remote Shared Policy',
|
|
143
|
+
file: '.oat/config.json',
|
|
144
|
+
scope: 'shared repo',
|
|
145
|
+
type,
|
|
146
|
+
defaultValue: schemaVersion
|
|
147
|
+
? '1'
|
|
148
|
+
: storage
|
|
149
|
+
? 'local'
|
|
150
|
+
: authority
|
|
151
|
+
? 'read-only'
|
|
152
|
+
: description
|
|
153
|
+
? 'none'
|
|
154
|
+
: 'unset',
|
|
155
|
+
mutability: aggregate || schemaVersion ? 'read-only' : 'read/write',
|
|
156
|
+
owningCommand: aggregate || schemaVersion
|
|
157
|
+
? 'individual child keys'
|
|
158
|
+
: `oat config set ${key} <value> --shared`,
|
|
159
|
+
description: 'Repository-owned remote storage or mutation policy; host execution is discovered live and cannot broaden it.',
|
|
160
|
+
};
|
|
161
|
+
});
|
|
97
162
|
const CONFIG_CATALOG = [
|
|
163
|
+
...PJM_REMOTE_CONFIG_CATALOG,
|
|
98
164
|
{
|
|
99
165
|
key: 'projects.root',
|
|
100
166
|
group: 'Shared Repo (.oat/config.json)',
|
|
@@ -884,6 +950,7 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
884
950
|
readOatConfigForDefaultScopeRepair,
|
|
885
951
|
readOatConfigForDocumentationExcludesRepair,
|
|
886
952
|
readOatConfigForInstructionPointerExcludesRepair,
|
|
953
|
+
readOatConfigWithWarnings,
|
|
887
954
|
writeOatConfig,
|
|
888
955
|
readOatLocalConfig,
|
|
889
956
|
writeOatLocalConfig,
|
|
@@ -893,6 +960,7 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
893
960
|
resolveEffectiveConfig,
|
|
894
961
|
resolveAssetsRoot,
|
|
895
962
|
readFile: (path) => readFileDefault(path, 'utf8'),
|
|
963
|
+
atomicWriteJson,
|
|
896
964
|
confirmAction,
|
|
897
965
|
validateMatrixCell,
|
|
898
966
|
createDispatchValidationPassContext,
|
|
@@ -905,6 +973,9 @@ function isConfigKey(value) {
|
|
|
905
973
|
value === 'workflow.dispatchCeiling.providers' ||
|
|
906
974
|
isDispatchCeilingProviderKey(value));
|
|
907
975
|
}
|
|
976
|
+
function isPjmRemoteConfigKey(key) {
|
|
977
|
+
return key.startsWith('pjm.remote');
|
|
978
|
+
}
|
|
908
979
|
function isDispatchCeilingProviderKey(value) {
|
|
909
980
|
return (value.startsWith(DISPATCH_CEILING_PROVIDER_KEY_PREFIX) &&
|
|
910
981
|
value.slice(DISPATCH_CEILING_PROVIDER_KEY_PREFIX.length).trim().length > 0);
|
|
@@ -1119,6 +1190,12 @@ function validateSurfaceForKey(key, surface) {
|
|
|
1119
1190
|
}
|
|
1120
1191
|
return;
|
|
1121
1192
|
}
|
|
1193
|
+
if (isPjmRemoteConfigKey(key)) {
|
|
1194
|
+
if (surface !== 'shared') {
|
|
1195
|
+
throw new Error(`Cannot set '${key}' at '${surface}' scope. PJM remote policy and storage can only be set at shared scope.`);
|
|
1196
|
+
}
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1122
1199
|
if (key.startsWith('explainers.')) {
|
|
1123
1200
|
const allowed = key === 'explainers.defaults.style' ||
|
|
1124
1201
|
key === 'explainers.defaults.palette' ||
|
|
@@ -1183,9 +1260,16 @@ function defaultSurfaceForKey(key) {
|
|
|
1183
1260
|
/**
|
|
1184
1261
|
* Resolve the `--shared` / `--local` / `--user` trio to a single surface.
|
|
1185
1262
|
*
|
|
1186
|
-
*
|
|
1187
|
-
* mutual-exclusion rule
|
|
1188
|
-
*
|
|
1263
|
+
* `set`, `unset`, and `adopt` all resolve the trio here -- this is the only
|
|
1264
|
+
* copy of the mutual-exclusion rule and of its message. It was lifted verbatim
|
|
1265
|
+
* out of the `set` action so `unset` could share it, and `adopt` was folded on
|
|
1266
|
+
* afterwards.
|
|
1267
|
+
*
|
|
1268
|
+
* The message is pinned in two ways, so changing it means moving all three
|
|
1269
|
+
* commands together: the per-command cases assert it individually, and the
|
|
1270
|
+
* three-command parity case in `index.test.ts` ('set, unset, and adopt reject
|
|
1271
|
+
* the same conflicting surface flags with one message') compares the three
|
|
1272
|
+
* commands' output to each other as well as to the literal.
|
|
1189
1273
|
*/
|
|
1190
1274
|
function resolveSurfaceFlags(options) {
|
|
1191
1275
|
const flagsPresent = [options.shared, options.local, options.user].filter(Boolean).length;
|
|
@@ -1435,7 +1519,10 @@ function applyWorkflowValue(workflow, key, value) {
|
|
|
1435
1519
|
const { provider, tier } = parseDispatchCeilingProviderConfigKey(key);
|
|
1436
1520
|
const providers = workflow.dispatchCeiling?.providers ?? {};
|
|
1437
1521
|
if (tier) {
|
|
1438
|
-
|
|
1522
|
+
// `provider` is a user-supplied config-key segment, so the lookup is
|
|
1523
|
+
// own-key guarded. The computed-key writes below use object-literal
|
|
1524
|
+
// define semantics and are already safe.
|
|
1525
|
+
const existingProviderValue = getOwnKey(providers, provider);
|
|
1439
1526
|
const existingTierMap = existingProviderValue &&
|
|
1440
1527
|
typeof existingProviderValue === 'object' &&
|
|
1441
1528
|
!Array.isArray(existingProviderValue)
|
|
@@ -1532,6 +1619,98 @@ function formatResolvedValue(value) {
|
|
|
1532
1619
|
}
|
|
1533
1620
|
return String(value);
|
|
1534
1621
|
}
|
|
1622
|
+
function defaultPjmRemoteSharedConfig() {
|
|
1623
|
+
return {
|
|
1624
|
+
schemaVersion: 1,
|
|
1625
|
+
storage: { state: 'local' },
|
|
1626
|
+
policy: {
|
|
1627
|
+
description: 'none',
|
|
1628
|
+
authority: { default: 'read-only', operations: {} },
|
|
1629
|
+
providers: {},
|
|
1630
|
+
},
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
function applyPjmRemoteSharedValue(current, key, rawValue) {
|
|
1634
|
+
if (key === 'pjm.remote' ||
|
|
1635
|
+
key === 'pjm.remote.policy' ||
|
|
1636
|
+
key === 'pjm.remote.schemaVersion') {
|
|
1637
|
+
throw new Error(`Config key '${key}' is read-only; set one of its documented child keys.`);
|
|
1638
|
+
}
|
|
1639
|
+
const remote = structuredClone(current ?? defaultPjmRemoteSharedConfig());
|
|
1640
|
+
if (key === 'pjm.remote.storage.state') {
|
|
1641
|
+
const state = rawValue.trim();
|
|
1642
|
+
if (state !== 'local' && state !== 'shared') {
|
|
1643
|
+
throw new Error(`Invalid value for ${key}: expected one of local | shared, got '${rawValue}'.`);
|
|
1644
|
+
}
|
|
1645
|
+
if (state === 'shared') {
|
|
1646
|
+
throw new Error("Shared operational storage requires 'oat pjm remote storage shared' preview and approval; direct config set is blocked.");
|
|
1647
|
+
}
|
|
1648
|
+
remote.storage = { state };
|
|
1649
|
+
return remote;
|
|
1650
|
+
}
|
|
1651
|
+
const descriptions = [
|
|
1652
|
+
'none',
|
|
1653
|
+
'managed-section',
|
|
1654
|
+
'replace',
|
|
1655
|
+
];
|
|
1656
|
+
const authorities = [
|
|
1657
|
+
'read-only',
|
|
1658
|
+
'user-approved',
|
|
1659
|
+
'user-authorized',
|
|
1660
|
+
'autonomous',
|
|
1661
|
+
];
|
|
1662
|
+
const value = rawValue.trim();
|
|
1663
|
+
if (key === 'pjm.remote.policy.description') {
|
|
1664
|
+
if (!descriptions.includes(value)) {
|
|
1665
|
+
throw new Error(`Invalid value for ${key}: expected one of ${descriptions.join(' | ')}, got '${rawValue}'.`);
|
|
1666
|
+
}
|
|
1667
|
+
remote.policy.description = value;
|
|
1668
|
+
return remote;
|
|
1669
|
+
}
|
|
1670
|
+
if (!authorities.includes(value)) {
|
|
1671
|
+
if (key.endsWith('.description')) {
|
|
1672
|
+
if (!descriptions.includes(value)) {
|
|
1673
|
+
throw new Error(`Invalid value for ${key}: expected one of ${descriptions.join(' | ')}, got '${rawValue}'.`);
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
else {
|
|
1677
|
+
throw new Error(`Invalid value for ${key}: expected one of ${authorities.join(' | ')}, got '${rawValue}'.`);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
if (key === 'pjm.remote.policy.authority.default') {
|
|
1681
|
+
remote.policy.authority.default = value;
|
|
1682
|
+
return remote;
|
|
1683
|
+
}
|
|
1684
|
+
const repositoryOperationPrefix = 'pjm.remote.policy.authority.operations.';
|
|
1685
|
+
if (key.startsWith(repositoryOperationPrefix)) {
|
|
1686
|
+
const operation = key.slice(repositoryOperationPrefix.length);
|
|
1687
|
+
remote.policy.authority.operations ??= {};
|
|
1688
|
+
remote.policy.authority.operations[operation] =
|
|
1689
|
+
value;
|
|
1690
|
+
return remote;
|
|
1691
|
+
}
|
|
1692
|
+
const parts = key.split('.');
|
|
1693
|
+
const provider = parts[4];
|
|
1694
|
+
remote.policy.providers ??= {};
|
|
1695
|
+
const providerPolicy = structuredClone(remote.policy.providers[provider] ?? {});
|
|
1696
|
+
if (parts[5] === 'description') {
|
|
1697
|
+
providerPolicy.description = value;
|
|
1698
|
+
}
|
|
1699
|
+
else {
|
|
1700
|
+
providerPolicy.authority ??= {};
|
|
1701
|
+
if (parts[6] === 'default') {
|
|
1702
|
+
providerPolicy.authority.default = value;
|
|
1703
|
+
}
|
|
1704
|
+
else {
|
|
1705
|
+
providerPolicy.authority.operations ??= {};
|
|
1706
|
+
const operation = parts[7];
|
|
1707
|
+
providerPolicy.authority.operations[operation] =
|
|
1708
|
+
value;
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
remote.policy.providers[provider] = providerPolicy;
|
|
1712
|
+
return remote;
|
|
1713
|
+
}
|
|
1535
1714
|
async function getConfigValue(repoRoot, userConfigDir, key, dependencies, preserveRawObject = false) {
|
|
1536
1715
|
const resolved = await dependencies.resolveEffectiveConfig(repoRoot, userConfigDir, dependencies.processEnv);
|
|
1537
1716
|
const entry = resolved.resolved[key];
|
|
@@ -1569,20 +1748,24 @@ function buildResolvedConfigAggregate(resolved, key) {
|
|
|
1569
1748
|
if (sourceRank[entry.source] > sourceRank[source]) {
|
|
1570
1749
|
source = entry.source;
|
|
1571
1750
|
}
|
|
1751
|
+
// Key segments come from resolved config keys, so a provider literally
|
|
1752
|
+
// named `__proto__` reaches this walk. A bare `cursor[part]` descends into
|
|
1753
|
+
// `Object.prototype` and the leaf write then lands on the global
|
|
1754
|
+
// prototype, polluting every object in the process -- not just this map.
|
|
1572
1755
|
const parts = entryKey.slice(prefix.length).split('.');
|
|
1573
1756
|
let cursor = value;
|
|
1574
1757
|
for (const [index, part] of parts.entries()) {
|
|
1575
1758
|
if (index === parts.length - 1) {
|
|
1576
|
-
cursor
|
|
1759
|
+
setOwnKey(cursor, part, entry.value);
|
|
1577
1760
|
}
|
|
1578
1761
|
else {
|
|
1579
|
-
const nested = cursor
|
|
1762
|
+
const nested = getOwnKey(cursor, part);
|
|
1580
1763
|
if (typeof nested !== 'object' ||
|
|
1581
1764
|
nested === null ||
|
|
1582
1765
|
Array.isArray(nested)) {
|
|
1583
|
-
cursor
|
|
1766
|
+
setOwnKey(cursor, part, {});
|
|
1584
1767
|
}
|
|
1585
|
-
cursor = cursor
|
|
1768
|
+
cursor = getOwnKey(cursor, part);
|
|
1586
1769
|
}
|
|
1587
1770
|
}
|
|
1588
1771
|
}
|
|
@@ -1600,6 +1783,19 @@ async function listConfigKeys(repoRoot, userConfigDir, dependencies) {
|
|
|
1600
1783
|
async function setConfigValue(repoRoot, userConfigDir, key, rawValue, surface, dependencies, warn) {
|
|
1601
1784
|
validateSurfaceForKey(key, surface);
|
|
1602
1785
|
const effectiveSurface = surface === 'auto' ? defaultSurfaceForKey(key) : surface;
|
|
1786
|
+
if (isPjmRemoteConfigKey(key)) {
|
|
1787
|
+
const config = await dependencies.readOatConfig(repoRoot);
|
|
1788
|
+
const remote = applyPjmRemoteSharedValue(config.pjm?.remote, key, rawValue);
|
|
1789
|
+
await dependencies.writeOatConfig(repoRoot, {
|
|
1790
|
+
...config,
|
|
1791
|
+
pjm: { ...config.pjm, remote },
|
|
1792
|
+
});
|
|
1793
|
+
return {
|
|
1794
|
+
key,
|
|
1795
|
+
value: rawValue.trim(),
|
|
1796
|
+
source: 'shared',
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1603
1799
|
if (isWorkflowKey(key)) {
|
|
1604
1800
|
const parsedValue = parseWorkflowValue(key, rawValue);
|
|
1605
1801
|
const displayValue = formatResolvedValue(parsedValue);
|
|
@@ -1990,7 +2186,8 @@ function configPathForKey(key) {
|
|
|
1990
2186
|
}
|
|
1991
2187
|
if (key.startsWith('explainers.') ||
|
|
1992
2188
|
key.startsWith('documentation.') ||
|
|
1993
|
-
key.startsWith('archive.')
|
|
2189
|
+
key.startsWith('archive.') ||
|
|
2190
|
+
isPjmRemoteConfigKey(key)) {
|
|
1994
2191
|
return key.split('.');
|
|
1995
2192
|
}
|
|
1996
2193
|
if (key === 'git.defaultBranch' ||
|
|
@@ -2024,8 +2221,25 @@ function configPathForKey(key) {
|
|
|
2024
2221
|
*/
|
|
2025
2222
|
async function unsetConfigValue(repoRoot, userConfigDir, key, surface, dependencies, warn) {
|
|
2026
2223
|
validateSurfaceForKey(key, surface);
|
|
2027
|
-
|
|
2028
|
-
|
|
2224
|
+
// These are structural views (and, for schemaVersion, the discriminator
|
|
2225
|
+
// that makes the remote policy readable), just as they are for `set`.
|
|
2226
|
+
// Refuse them before resolving config so an unset attempt can never be
|
|
2227
|
+
// mistaken for permission to remove the whole policy boundary.
|
|
2228
|
+
if (key === 'pjm.remote' ||
|
|
2229
|
+
key === 'pjm.remote.policy' ||
|
|
2230
|
+
key === 'pjm.remote.schemaVersion') {
|
|
2231
|
+
throw new Error(`Config key '${key}' is read-only; unset one of its documented child keys.`);
|
|
2232
|
+
}
|
|
2233
|
+
// Deliberately not `resolveEffectiveConfig`: its result was used for this one
|
|
2234
|
+
// boolean, and its strict normalization throws on exactly the malformed
|
|
2235
|
+
// stored value `unset` exists to remove. `ENV_OVERRIDE_MAP` covers three
|
|
2236
|
+
// keys, all of which are in `DEFAULT_SHARED_CONFIG` and therefore always
|
|
2237
|
+
// present in the resolved view, and the env branch is checked first there --
|
|
2238
|
+
// so this probe answers identically for every config key. The whole-config
|
|
2239
|
+
// read this replaces was also a validation barrier; that role is reinstated
|
|
2240
|
+
// separately by the targeted barrier below, which reads every surface except
|
|
2241
|
+
// the targeted one (the targeted one is re-normalized on write instead).
|
|
2242
|
+
const envShadowed = resolveEnvOverride(key, dependencies.processEnv) !== undefined;
|
|
2029
2243
|
if (key === 'activeProject' || key === 'lastPausedProject') {
|
|
2030
2244
|
throw new Error(`Cannot unset state key '${key}'. Lifecycle state is cleared with: oat config set ${key} ''`);
|
|
2031
2245
|
}
|
|
@@ -2046,6 +2260,44 @@ async function unsetConfigValue(repoRoot, userConfigDir, key, surface, dependenc
|
|
|
2046
2260
|
? defaultSurfaceForKey(key)
|
|
2047
2261
|
: surface;
|
|
2048
2262
|
const path = configPathForKey(key);
|
|
2263
|
+
// Targeted strict barrier.
|
|
2264
|
+
//
|
|
2265
|
+
// `resolveEffectiveConfig` used to run at the top of this function, and as a
|
|
2266
|
+
// side effect of resolving it strictly read all three surfaces. That read --
|
|
2267
|
+
// not its return value -- is what made a malformed value anywhere abort
|
|
2268
|
+
// `unset` before it wrote anything. The `envShadowed` probe above no longer
|
|
2269
|
+
// performs it, so the barrier is reinstated here explicitly and narrowly:
|
|
2270
|
+
// every surface OTHER than the targeted one is read strictly, through the
|
|
2271
|
+
// same injected readers `resolveEffectiveConfig` composes, so a malformed
|
|
2272
|
+
// value on an untargeted surface still aborts with the identical
|
|
2273
|
+
// `Invalid <key>` message it produced before.
|
|
2274
|
+
//
|
|
2275
|
+
// The targeted surface is deliberately excluded, and that exclusion is the
|
|
2276
|
+
// whole point of the change: `removeFromSurface` reads it through the
|
|
2277
|
+
// key-specific repair reader -- lenient only for the key being removed -- and
|
|
2278
|
+
// writes it back through `writeOatConfig` / `writeOatLocalConfig` /
|
|
2279
|
+
// `writeUserConfig`, every one of which re-normalizes. A malformed value on
|
|
2280
|
+
// the targeted surface that is NOT the key being removed is therefore still
|
|
2281
|
+
// refused, on the rewrite rather than on a pre-read.
|
|
2282
|
+
if (effectiveSurface !== 'shared') {
|
|
2283
|
+
await dependencies.readOatConfig(repoRoot);
|
|
2284
|
+
}
|
|
2285
|
+
if (effectiveSurface !== 'local') {
|
|
2286
|
+
await dependencies.readOatLocalConfig(repoRoot);
|
|
2287
|
+
}
|
|
2288
|
+
if (effectiveSurface !== 'user') {
|
|
2289
|
+
await dependencies.readUserConfig(userConfigDir);
|
|
2290
|
+
}
|
|
2291
|
+
// The one branch that gets no re-normalization on the way out: the
|
|
2292
|
+
// `pjm.remote` raw-write path in `removeFromSurface` persists through
|
|
2293
|
+
// `atomicWriteJson`, bypassing `writeOatConfig`. So the targeted shared
|
|
2294
|
+
// surface must be read strictly here too. `pjm.remote` children are not among
|
|
2295
|
+
// the malformed-value repair keys this change targets, which is why adding
|
|
2296
|
+
// this read keeps that branch's acceptance set byte-identical to its previous
|
|
2297
|
+
// one rather than narrowing it.
|
|
2298
|
+
if (isPjmRemoteConfigKey(key)) {
|
|
2299
|
+
await dependencies.readOatConfig(repoRoot);
|
|
2300
|
+
}
|
|
2049
2301
|
const removed = await removeFromSurface(repoRoot, userConfigDir, key, effectiveSurface, path, dependencies);
|
|
2050
2302
|
// The env guard is scoped to the targeted surface, not to the effective
|
|
2051
2303
|
// value, so that `unset` mirrors `set`: `set` happily rewrites a stored value
|
|
@@ -2107,6 +2359,25 @@ async function removeFromSurface(repoRoot, userConfigDir, key, effectiveSurface,
|
|
|
2107
2359
|
return false;
|
|
2108
2360
|
}
|
|
2109
2361
|
const configPath = join(repoRoot, '.oat', 'config.json');
|
|
2362
|
+
if (isPjmRemoteConfigKey(key)) {
|
|
2363
|
+
// PJM remote normalization materializes fail-closed defaults such as
|
|
2364
|
+
// policy.description=none and authority.default=read-only. Removing a
|
|
2365
|
+
// leaf from that normalized object and sending it through writeOatConfig
|
|
2366
|
+
// would therefore write the leaf straight back while reporting success.
|
|
2367
|
+
// The strict shared read happens in `unsetConfigValue`'s targeted barrier
|
|
2368
|
+
// immediately before this call -- this branch depends on it, because
|
|
2369
|
+
// `atomicWriteJson` below bypasses `writeOatConfig`'s normalization, so
|
|
2370
|
+
// nothing downstream would catch a malformed document. Given that read,
|
|
2371
|
+
// perform this removal against the validated raw document and atomically
|
|
2372
|
+
// persist only the requested structural change.
|
|
2373
|
+
const repaired = await removeConfigPathOnDisk(configPath, path);
|
|
2374
|
+
if (!repaired) {
|
|
2375
|
+
return false;
|
|
2376
|
+
}
|
|
2377
|
+
preservePjmRemotePolicyBoundary(repaired, path);
|
|
2378
|
+
await dependencies.atomicWriteJson(configPath, repaired);
|
|
2379
|
+
return true;
|
|
2380
|
+
}
|
|
2110
2381
|
const sharedConfig = key === 'documentation.excludes'
|
|
2111
2382
|
? await dependencies.readOatConfigForDocumentationExcludesRepair(repoRoot)
|
|
2112
2383
|
: key === 'documentation.instructionPointerExcludes'
|
|
@@ -2126,6 +2397,31 @@ async function removeFromSurface(repoRoot, userConfigDir, key, effectiveSurface,
|
|
|
2126
2397
|
}
|
|
2127
2398
|
return false;
|
|
2128
2399
|
}
|
|
2400
|
+
/**
|
|
2401
|
+
* Keep the required PJM remote policy object when unsetting its final leaf.
|
|
2402
|
+
*
|
|
2403
|
+
* The recursive remover normally prunes empty parents. For this one schema,
|
|
2404
|
+
* however, `policy` is the structural boundary that keeps sibling remote state
|
|
2405
|
+
* (notably `storage.state=shared`) readable. An empty policy is valid and
|
|
2406
|
+
* normalizes to the fail-closed defaults; an absent policy makes the complete
|
|
2407
|
+
* remote object unreadable.
|
|
2408
|
+
*/
|
|
2409
|
+
function preservePjmRemotePolicyBoundary(config, path) {
|
|
2410
|
+
if (path[0] !== 'pjm' || path[1] !== 'remote' || path[2] !== 'policy') {
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
const pjm = config.pjm;
|
|
2414
|
+
if (!isRecord(pjm)) {
|
|
2415
|
+
return;
|
|
2416
|
+
}
|
|
2417
|
+
const remote = pjm.remote;
|
|
2418
|
+
if (!isRecord(remote)) {
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
if (!Object.prototype.hasOwnProperty.call(remote, 'policy')) {
|
|
2422
|
+
remote.policy = {};
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2129
2425
|
/**
|
|
2130
2426
|
* Remove `path` from the raw JSON on disk, ignoring normalization.
|
|
2131
2427
|
*
|
|
@@ -2193,15 +2489,22 @@ function applyDispatchMatrixRecommendation(workflow, recommendation) {
|
|
|
2193
2489
|
const providers = {
|
|
2194
2490
|
...recommendation.providers,
|
|
2195
2491
|
};
|
|
2492
|
+
// `existingProviders` is a `normalizeDispatchMatrix` product, which now
|
|
2493
|
+
// keeps a provider literally named `__proto__` as an own key, so
|
|
2494
|
+
// `Object.entries` yields it here and every access is own-key guarded. The
|
|
2495
|
+
// `{ ...recommendation.providers }` spread above is already safe.
|
|
2196
2496
|
for (const [provider, existingValue] of Object.entries(existingProviders)) {
|
|
2197
|
-
const recommendedValue = recommendation.providers
|
|
2497
|
+
const recommendedValue = getOwnKey(recommendation.providers, provider);
|
|
2198
2498
|
if (recommendedValue &&
|
|
2199
2499
|
typeof recommendedValue !== 'string' &&
|
|
2200
2500
|
typeof existingValue !== 'string') {
|
|
2201
|
-
providers
|
|
2501
|
+
setOwnKey(providers, provider, {
|
|
2502
|
+
...recommendedValue,
|
|
2503
|
+
...existingValue,
|
|
2504
|
+
});
|
|
2202
2505
|
}
|
|
2203
2506
|
else {
|
|
2204
|
-
providers
|
|
2507
|
+
setOwnKey(providers, provider, existingValue);
|
|
2205
2508
|
}
|
|
2206
2509
|
}
|
|
2207
2510
|
return {
|
|
@@ -2218,11 +2521,10 @@ async function effectiveTerminalReviewerNotices(repoRoot, userConfigDir, depende
|
|
|
2218
2521
|
const effectiveProviders = {};
|
|
2219
2522
|
for (const config of [resolved.user, resolved.shared, resolved.local]) {
|
|
2220
2523
|
for (const [provider, value] of Object.entries(config.workflow?.dispatchCeiling?.providers ?? {})) {
|
|
2221
|
-
const existing = effectiveProviders
|
|
2222
|
-
effectiveProviders
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
: value;
|
|
2524
|
+
const existing = getOwnKey(effectiveProviders, provider);
|
|
2525
|
+
setOwnKey(effectiveProviders, provider, isRecord(existing) && isRecord(value)
|
|
2526
|
+
? { ...existing, ...value }
|
|
2527
|
+
: value);
|
|
2226
2528
|
}
|
|
2227
2529
|
}
|
|
2228
2530
|
return terminalReviewerNoticesForMatrix(effectiveProviders);
|
|
@@ -2329,6 +2631,32 @@ function formatCatalogDetails(entries) {
|
|
|
2329
2631
|
].join('\n'))
|
|
2330
2632
|
.join('\n\n');
|
|
2331
2633
|
}
|
|
2634
|
+
/**
|
|
2635
|
+
* The `warnings` field for a JSON document, omitted when there is nothing to
|
|
2636
|
+
* say.
|
|
2637
|
+
*
|
|
2638
|
+
* An always-present `warnings: []` would be new noise on the common path and
|
|
2639
|
+
* would break every existing exact-match assertion on these documents, so the
|
|
2640
|
+
* key appears only when it carries something -- the same shape
|
|
2641
|
+
* `exclusionWarnings` uses in `commands/instructions/sync/sync.ts`.
|
|
2642
|
+
*/
|
|
2643
|
+
function jsonWarnings(warnings) {
|
|
2644
|
+
return warnings.length > 0 ? { warnings } : {};
|
|
2645
|
+
}
|
|
2646
|
+
/**
|
|
2647
|
+
* Emit shared-config read warnings on the human channel.
|
|
2648
|
+
*
|
|
2649
|
+
* `logger.warn` is a no-op under `--json` (`ui/logger.ts`), so the JSON
|
|
2650
|
+
* document carries the same strings in its own `warnings` field instead. Each
|
|
2651
|
+
* caller picks exactly one channel, which is why this is only ever reached from
|
|
2652
|
+
* the non-JSON branch: routing both ways would print nothing extra today but
|
|
2653
|
+
* would double-print the moment the logger learned to emit under `--json`.
|
|
2654
|
+
*/
|
|
2655
|
+
function emitConfigReadWarnings(context, warnings) {
|
|
2656
|
+
for (const warning of warnings) {
|
|
2657
|
+
context.logger.warn(warning);
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2332
2660
|
async function runGet(keyArg, context, dependencies) {
|
|
2333
2661
|
try {
|
|
2334
2662
|
if (!isConfigKey(keyArg)) {
|
|
@@ -2336,14 +2664,21 @@ async function runGet(keyArg, context, dependencies) {
|
|
|
2336
2664
|
}
|
|
2337
2665
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
2338
2666
|
const userConfigDir = join(context.home, '.oat');
|
|
2667
|
+
// One read per invocation, not one per resolved layer, so a wrong-typed
|
|
2668
|
+
// key is reported once. A fail-closed key throws here exactly as it would
|
|
2669
|
+
// have thrown inside `resolveEffectiveConfig` below -- same normalizer,
|
|
2670
|
+
// same message -- so error precedence is unchanged.
|
|
2671
|
+
const { warnings } = await dependencies.readOatConfigWithWarnings(repoRoot);
|
|
2339
2672
|
const value = await getConfigValue(repoRoot, userConfigDir, keyArg, dependencies, context.json);
|
|
2340
2673
|
if (context.json) {
|
|
2341
2674
|
context.logger.json({
|
|
2342
2675
|
status: 'ok',
|
|
2343
2676
|
...value,
|
|
2677
|
+
...jsonWarnings(warnings),
|
|
2344
2678
|
});
|
|
2345
2679
|
}
|
|
2346
2680
|
else {
|
|
2681
|
+
emitConfigReadWarnings(context, warnings);
|
|
2347
2682
|
context.logger.info(formatResolvedValue(value.value) ?? '');
|
|
2348
2683
|
}
|
|
2349
2684
|
process.exitCode = 0;
|
|
@@ -2463,6 +2798,9 @@ async function runList(context, dependencies) {
|
|
|
2463
2798
|
try {
|
|
2464
2799
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
2465
2800
|
const userConfigDir = join(context.home, '.oat');
|
|
2801
|
+
// `list` resolves every key and each resolution re-reads the shared file,
|
|
2802
|
+
// so the warning has to come from this one read rather than from the loop.
|
|
2803
|
+
const { warnings } = await dependencies.readOatConfigWithWarnings(repoRoot);
|
|
2466
2804
|
const values = [];
|
|
2467
2805
|
for (const key of await listConfigKeys(repoRoot, userConfigDir, dependencies)) {
|
|
2468
2806
|
values.push(await getConfigValue(repoRoot, userConfigDir, key, dependencies));
|
|
@@ -2471,9 +2809,11 @@ async function runList(context, dependencies) {
|
|
|
2471
2809
|
context.logger.json({
|
|
2472
2810
|
status: 'ok',
|
|
2473
2811
|
values,
|
|
2812
|
+
...jsonWarnings(warnings),
|
|
2474
2813
|
});
|
|
2475
2814
|
}
|
|
2476
2815
|
else {
|
|
2816
|
+
emitConfigReadWarnings(context, warnings);
|
|
2477
2817
|
context.logger.info(formatList(values));
|
|
2478
2818
|
}
|
|
2479
2819
|
process.exitCode = 0;
|
|
@@ -2594,21 +2934,7 @@ export function createConfigCommand(overrides = {}) {
|
|
|
2594
2934
|
.action(async (template, options, command) => {
|
|
2595
2935
|
const context = dependencies.buildCommandContext(readGlobalOptions(command));
|
|
2596
2936
|
try {
|
|
2597
|
-
const
|
|
2598
|
-
options.shared,
|
|
2599
|
-
options.local,
|
|
2600
|
-
options.user,
|
|
2601
|
-
].filter(Boolean).length;
|
|
2602
|
-
if (flagsPresent > 1) {
|
|
2603
|
-
throw new Error('--shared, --local, and --user flags are mutually exclusive; pass at most one.');
|
|
2604
|
-
}
|
|
2605
|
-
let surface = 'auto';
|
|
2606
|
-
if (options.shared)
|
|
2607
|
-
surface = 'shared';
|
|
2608
|
-
else if (options.local)
|
|
2609
|
-
surface = 'local';
|
|
2610
|
-
else if (options.user)
|
|
2611
|
-
surface = 'user';
|
|
2937
|
+
const surface = resolveSurfaceFlags(options);
|
|
2612
2938
|
await runAdopt(template, { surface }, context, dependencies);
|
|
2613
2939
|
}
|
|
2614
2940
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/index-generate/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,eAAO,MAAM,uBAAuB,iIAC4F,CAAC;AAuBjI,UAAU,6BAA6B;IACrC,aAAa,EAAE,CACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,aAAa,EAAE,oBAAoB,KAChD,OAAO,CAAC,OAAO,aAAa,EAAE,UAAU,EAAE,CAAC,CAAC;IACjD,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,aAAa,EAAE,UAAU,EAAE,KAAK,MAAM,CAAC;IACrE,SAAS,EAAE,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,cAAc,KACrB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,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,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC7D;AAED,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,QAAQ,EAAE,6BAA6B,CAAC;CACzC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/docs/index-generate/index.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,KAAK,SAAS,EAGf,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,eAAO,MAAM,uBAAuB,iIAC4F,CAAC;AAuBjI,UAAU,6BAA6B;IACrC,aAAa,EAAE,CACb,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,aAAa,EAAE,oBAAoB,KAChD,OAAO,CAAC,OAAO,aAAa,EAAE,UAAU,EAAE,CAAC,CAAC;IACjD,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,aAAa,EAAE,UAAU,EAAE,KAAK,MAAM,CAAC;IACrE,SAAS,EAAE,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,cAAc,KACrB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,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,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAClD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9C,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC7D;AAED,UAAU,yBAAyB;IACjC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,QAAQ,EAAE,6BAA6B,CAAC;CACzC;AAomBD,wBAAgB,8BAA8B,CAC5C,SAAS,GAAE,OAAO,CAAC,yBAAyB,CAAM,GACjD,OAAO,CAgCT"}
|