@open-agent-toolkit/cli 0.2.51 → 0.2.53
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/bootstrap.md +6 -2
- package/assets/docs/cli-utilities/tool-packs.md +87 -33
- package/assets/docs/provider-sync/commands.md +30 -2
- package/assets/docs/provider-sync/config.md +19 -0
- package/assets/docs/provider-sync/manifest-and-drift.md +37 -0
- package/assets/docs/provider-sync/providers.md +69 -2
- package/assets/docs/provider-sync/scope-and-surface.md +44 -0
- package/assets/docs/reference/cli-reference.md +1 -0
- package/assets/docs/reference/oat-directory-structure.md +11 -4
- package/assets/docs/workflows/projects/evidence-layers.md +110 -1
- package/assets/docs/workflows/projects/implementation-execution.md +13 -0
- package/assets/docs/workflows/projects/orchestration-model.md +18 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-dispatch-subagents/SKILL.md +57 -1
- package/assets/skills/oat-dispatch-subagents/references/record-schema.md +77 -1
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +1 -1
- package/assets/skills/oat-project-dispatch-subagents/SKILL.md +24 -1
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +11 -0
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +1 -1
- package/assets/skills/oat-project-plan-writing/SKILL.md +12 -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-review-provide/SKILL.md +12 -1
- package/assets/skills/oat-project-review-provide-remote/SKILL.md +12 -1
- package/dist/agents/canonical/index.d.ts +2 -0
- package/dist/agents/canonical/index.d.ts.map +1 -1
- package/dist/agents/canonical/index.js +1 -0
- package/dist/agents/canonical/resolve.d.ts +45 -0
- package/dist/agents/canonical/resolve.d.ts.map +1 -0
- package/dist/agents/canonical/resolve.js +175 -0
- package/dist/commands/decision/agents-guidance.d.ts +2 -2
- package/dist/commands/decision/agents-guidance.d.ts.map +1 -1
- package/dist/commands/decision/agents-guidance.js +1 -4
- package/dist/commands/decision/index.d.ts.map +1 -1
- package/dist/commands/decision/index.js +25 -6
- package/dist/commands/docs/init/index.d.ts +7 -1
- package/dist/commands/docs/init/index.d.ts.map +1 -1
- package/dist/commands/docs/init/index.js +53 -20
- package/dist/commands/doctor/index.d.ts +8 -2
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +157 -46
- package/dist/commands/init/index.d.ts +8 -3
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +66 -28
- package/dist/commands/init/tools/index.d.ts +12 -12
- package/dist/commands/init/tools/index.d.ts.map +1 -1
- package/dist/commands/init/tools/index.js +430 -99
- package/dist/commands/init/tools/install-state.d.ts +2 -0
- package/dist/commands/init/tools/install-state.d.ts.map +1 -1
- package/dist/commands/init/tools/install-state.js +11 -0
- package/dist/commands/init/tools/project-guidance.d.ts +49 -0
- package/dist/commands/init/tools/project-guidance.d.ts.map +1 -0
- package/dist/commands/init/tools/project-guidance.js +144 -0
- package/dist/commands/init/tools/workflows/index.d.ts +7 -0
- package/dist/commands/init/tools/workflows/index.d.ts.map +1 -1
- package/dist/commands/init/tools/workflows/index.js +160 -7
- package/dist/commands/pjm/index.d.ts.map +1 -1
- package/dist/commands/pjm/index.js +28 -3
- package/dist/commands/pjm/init.d.ts +5 -0
- package/dist/commands/pjm/init.d.ts.map +1 -1
- package/dist/commands/pjm/init.js +19 -3
- package/dist/commands/project/dispatch/index.d.ts +10 -0
- package/dist/commands/project/dispatch/index.d.ts.map +1 -0
- package/dist/commands/project/dispatch/index.js +137 -0
- package/dist/commands/project/dispatch/record.d.ts +91 -0
- package/dist/commands/project/dispatch/record.d.ts.map +1 -0
- package/dist/commands/project/dispatch/record.js +402 -0
- package/dist/commands/project/index.d.ts.map +1 -1
- package/dist/commands/project/index.js +2 -0
- package/dist/commands/providers/inspect/inspect.d.ts +8 -1
- package/dist/commands/providers/inspect/inspect.d.ts.map +1 -1
- package/dist/commands/providers/inspect/inspect.js +146 -26
- package/dist/commands/providers/list/list.d.ts +8 -1
- package/dist/commands/providers/list/list.d.ts.map +1 -1
- package/dist/commands/providers/list/list.js +139 -23
- package/dist/commands/providers/providers.types.d.ts +25 -1
- package/dist/commands/providers/providers.types.d.ts.map +1 -1
- package/dist/commands/providers/set/index.d.ts +9 -1
- package/dist/commands/providers/set/index.d.ts.map +1 -1
- package/dist/commands/providers/set/index.js +43 -33
- package/dist/commands/remove/skill/remove-skill.d.ts.map +1 -1
- package/dist/commands/remove/skill/remove-skill.js +11 -0
- package/dist/commands/shared/agents-md.d.ts +42 -14
- package/dist/commands/shared/agents-md.d.ts.map +1 -1
- package/dist/commands/shared/agents-md.js +364 -70
- package/dist/commands/status/index.d.ts +8 -3
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +149 -37
- package/dist/commands/sync/apply.d.ts.map +1 -1
- package/dist/commands/sync/apply.js +220 -29
- package/dist/commands/sync/dry-run.d.ts.map +1 -1
- package/dist/commands/sync/dry-run.js +30 -6
- package/dist/commands/sync/index.d.ts +17 -2
- package/dist/commands/sync/index.d.ts.map +1 -1
- package/dist/commands/sync/index.js +108 -43
- package/dist/commands/sync/sync.types.d.ts +39 -2
- package/dist/commands/sync/sync.types.d.ts.map +1 -1
- package/dist/commands/sync/sync.utils.d.ts +5 -1
- package/dist/commands/sync/sync.utils.d.ts.map +1 -1
- package/dist/commands/sync/sync.utils.js +73 -0
- package/dist/commands/tools/info/info-tool.d.ts +2 -0
- package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
- package/dist/commands/tools/info/info-tool.js +34 -12
- package/dist/commands/tools/install/index.d.ts.map +1 -1
- package/dist/commands/tools/install/index.js +19 -3
- package/dist/commands/tools/list/list-tools.d.ts +2 -0
- package/dist/commands/tools/list/list-tools.d.ts.map +1 -1
- package/dist/commands/tools/list/list-tools.js +36 -7
- package/dist/commands/tools/remove/index.d.ts.map +1 -1
- package/dist/commands/tools/remove/index.js +150 -21
- package/dist/commands/tools/remove/remove-tools.d.ts +20 -0
- package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
- package/dist/commands/tools/remove/remove-tools.js +122 -1
- package/dist/commands/tools/shared/format-pack-inventory.d.ts +19 -0
- package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -1
- package/dist/commands/tools/shared/format-pack-inventory.js +109 -0
- package/dist/commands/tools/shared/pack-evidence.d.ts +66 -0
- package/dist/commands/tools/shared/pack-evidence.d.ts.map +1 -0
- package/dist/commands/tools/shared/pack-evidence.js +132 -0
- package/dist/commands/tools/shared/pack-inventory.d.ts +1 -0
- package/dist/commands/tools/shared/pack-inventory.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts +44 -0
- package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts.map +1 -0
- package/dist/commands/tools/shared/pack-lifecycle-outcome.js +91 -0
- package/dist/commands/tools/update/index.d.ts.map +1 -1
- package/dist/commands/tools/update/index.js +74 -4
- package/dist/commands/tools/update/update-tools.d.ts +5 -0
- package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
- package/dist/commands/tools/update/update-tools.js +64 -2
- package/dist/config/oat-config.d.ts +5 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +17 -5
- package/dist/config/user-sync-config.d.ts +1 -0
- package/dist/config/user-sync-config.d.ts.map +1 -1
- package/dist/config/user-sync-config.js +8 -0
- package/dist/drift/detector.d.ts +2 -2
- package/dist/drift/detector.d.ts.map +1 -1
- package/dist/drift/detector.js +18 -0
- package/dist/drift/strays.d.ts.map +1 -1
- package/dist/drift/strays.js +5 -0
- package/dist/engine/collection-sync.d.ts +14 -0
- package/dist/engine/collection-sync.d.ts.map +1 -0
- package/dist/engine/collection-sync.js +282 -0
- package/dist/engine/compute-plan.d.ts +8 -1
- package/dist/engine/compute-plan.d.ts.map +1 -1
- package/dist/engine/compute-plan.js +303 -12
- package/dist/engine/engine.types.d.ts +61 -0
- package/dist/engine/engine.types.d.ts.map +1 -1
- package/dist/engine/execute-plan.d.ts +22 -2
- package/dist/engine/execute-plan.d.ts.map +1 -1
- package/dist/engine/execute-plan.js +459 -27
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/index.d.ts.map +1 -1
- package/dist/engine/index.js +1 -1
- package/dist/engine/provider-path-safety.d.ts +1 -0
- package/dist/engine/provider-path-safety.d.ts.map +1 -1
- package/dist/engine/provider-path-safety.js +15 -0
- package/dist/engine/scanner.d.ts +9 -2
- package/dist/engine/scanner.d.ts.map +1 -1
- package/dist/engine/scanner.js +58 -4
- package/dist/fs/io.d.ts +67 -0
- package/dist/fs/io.d.ts.map +1 -1
- package/dist/fs/io.js +536 -3
- package/dist/manifest/index.d.ts +2 -2
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/manifest/index.js +1 -1
- package/dist/manifest/manager.d.ts +2 -2
- package/dist/manifest/manager.d.ts.map +1 -1
- package/dist/manifest/manager.js +20 -3
- package/dist/manifest/manifest.types.d.ts +704 -13
- package/dist/manifest/manifest.types.d.ts.map +1 -1
- package/dist/manifest/manifest.types.js +131 -15
- package/dist/providers/codex/codec/sync-extension.d.ts +1 -1
- package/dist/providers/codex/codec/sync-extension.d.ts.map +1 -1
- package/dist/providers/codex/codec/sync-extension.js +48 -17
- package/dist/providers/cursor/codec/sync-extension.d.ts +1 -1
- package/dist/providers/cursor/codec/sync-extension.d.ts.map +1 -1
- package/dist/providers/cursor/codec/sync-extension.js +52 -23
- package/dist/providers/identity/absolute-paths.d.ts +68 -0
- package/dist/providers/identity/absolute-paths.d.ts.map +1 -0
- package/dist/providers/identity/absolute-paths.js +144 -0
- package/dist/providers/identity/claude-runtime-observation.d.ts +105 -0
- package/dist/providers/identity/claude-runtime-observation.d.ts.map +1 -0
- package/dist/providers/identity/claude-runtime-observation.fixtures.d.ts +40 -0
- package/dist/providers/identity/claude-runtime-observation.fixtures.d.ts.map +1 -0
- package/dist/providers/identity/claude-runtime-observation.fixtures.js +146 -0
- package/dist/providers/identity/claude-runtime-observation.js +229 -0
- package/dist/providers/identity/codex-runtime-observation.d.ts +75 -0
- package/dist/providers/identity/codex-runtime-observation.d.ts.map +1 -0
- package/dist/providers/identity/codex-runtime-observation.fixtures.d.ts +37 -0
- package/dist/providers/identity/codex-runtime-observation.fixtures.d.ts.map +1 -0
- package/dist/providers/identity/codex-runtime-observation.fixtures.js +539 -0
- package/dist/providers/identity/codex-runtime-observation.js +255 -0
- package/dist/providers/identity/generic-dispatch-record.d.ts +313 -0
- package/dist/providers/identity/generic-dispatch-record.d.ts.map +1 -0
- package/dist/providers/identity/generic-dispatch-record.js +539 -0
- package/dist/providers/identity/oat-dispatch-record.d.ts +1964 -0
- package/dist/providers/identity/oat-dispatch-record.d.ts.map +1 -0
- package/dist/providers/identity/oat-dispatch-record.js +691 -0
- package/dist/providers/identity/runtime-observation.d.ts +100 -0
- package/dist/providers/identity/runtime-observation.d.ts.map +1 -0
- package/dist/providers/identity/runtime-observation.js +169 -0
- package/dist/providers/shared/index.d.ts +2 -0
- package/dist/providers/shared/index.d.ts.map +1 -1
- package/dist/providers/shared/index.js +1 -0
- package/dist/providers/shared/materialization-extension.d.ts +12 -0
- package/dist/providers/shared/materialization-extension.d.ts.map +1 -1
- package/dist/providers/shared/registry.d.ts +69 -0
- package/dist/providers/shared/registry.d.ts.map +1 -0
- package/dist/providers/shared/registry.js +252 -0
- package/dist/providers/shared/restart-adviser.d.ts +26 -0
- package/dist/providers/shared/restart-adviser.d.ts.map +1 -0
- package/dist/providers/shared/restart-adviser.js +96 -0
- package/dist/shared/types.d.ts +4 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -7,26 +7,24 @@ import { applyNativeSkillDisposition, getNativeSkillProviderDetails, isNativeSki
|
|
|
7
7
|
import { withScopeOption } from '../shared/scope-option.js';
|
|
8
8
|
import { confirmAction, selectManyWithAbort, selectWithAbort, } from '../shared/shared.prompts.js';
|
|
9
9
|
import { readGlobalOptions, resolveConcreteScopes, } from '../shared/shared.utils.js';
|
|
10
|
+
import { packEvidenceBlock, projectRenderablePackEvidence, unavailablePackEvidence, } from '../tools/shared/format-pack-inventory.js';
|
|
10
11
|
import { attributeSharedOwnerDiagnostics, hasScopedPackPlacementEvidence, inventoryPack, } from '../tools/shared/pack-inventory.js';
|
|
11
12
|
import { PACK_NAMES } from '../tools/shared/pack-manifest.js';
|
|
12
13
|
import { formatPackPath, formatPackPaths, updatePackRecovery, } from '../tools/shared/pack-paths.js';
|
|
13
14
|
import { DEFAULT_SYNC_CONFIG, loadSyncConfig, } from '../../config/index.js';
|
|
14
15
|
import { resolveUserSyncConfig } from '../../config/user-sync-config.js';
|
|
15
16
|
import { detectDrift, detectStrays, filterKnownStrays, } from '../../drift/index.js';
|
|
16
|
-
import { HOOK_DRIFT_WARNING, HOOK_STRAY_INFO, scanBundledManagedAgents, scanCanonical, } from '../../engine/index.js';
|
|
17
|
+
import { HOOK_DRIFT_WARNING, HOOK_STRAY_INFO, mergeUserScopeMaterializationEntries, scanBundledManagedAgents, scanCanonical, } from '../../engine/index.js';
|
|
17
18
|
import { resolveAssetsRoot } from '../../fs/assets.js';
|
|
18
19
|
import { normalizeToPosixPath, resolveProjectRoot, resolveScopeRoot, } from '../../fs/paths.js';
|
|
19
20
|
import { loadManifest, saveManifest } from '../../manifest/manager.js';
|
|
20
|
-
import { claudeAdapter } from '../../providers/claude/index.js';
|
|
21
|
-
import { codexAdapter } from '../../providers/codex/index.js';
|
|
22
21
|
import { applyCodexProjectExtensionPlan, computeCodexProjectExtensionPlan, } from '../../providers/codex/codec/sync-extension.js';
|
|
23
|
-
import { copilotAdapter } from '../../providers/copilot/index.js';
|
|
24
|
-
import { cursorAdapter } from '../../providers/cursor/index.js';
|
|
25
22
|
import { applyCursorProjectExtensionPlan, computeCursorProjectExtensionPlan, } from '../../providers/cursor/codec/sync-extension.js';
|
|
26
|
-
import {
|
|
27
|
-
import { getConfigAwareAdapters, getSyncMappings, } from '../../providers/shared/index.js';
|
|
23
|
+
import { getConfigAwareAdapters, getProviderRegistrations, getSyncMappings, resolveProviderScopeContext, } from '../../providers/shared/index.js';
|
|
28
24
|
import { getAdoptionSources } from '../../providers/shared/adapter.utils.js';
|
|
29
|
-
import {
|
|
25
|
+
import { userAgentMaterializationCoverage, } from '../../providers/shared/registry.js';
|
|
26
|
+
import { adviseProviderRefresh, } from '../../providers/shared/restart-adviser.js';
|
|
27
|
+
import {} from '../../shared/types.js';
|
|
30
28
|
import { formatStatusTable } from '../../ui/output.js';
|
|
31
29
|
import { Command } from 'commander';
|
|
32
30
|
const DEFAULT_REMEDIATION = 'Run "oat init" to adopt stray entries.';
|
|
@@ -61,8 +59,49 @@ function unavailablePackReport(error, roots, unavailableScopes) {
|
|
|
61
59
|
states: [],
|
|
62
60
|
unavailableScopes,
|
|
63
61
|
pjm: null,
|
|
62
|
+
evidence: packEvidenceBlock(PACK_NAMES.map((pack) => unavailablePackEvidence({
|
|
63
|
+
pack,
|
|
64
|
+
scopes: Object.keys(roots).map((key) => key === 'projectRoot' ? 'project' : 'user'),
|
|
65
|
+
reason: detail,
|
|
66
|
+
roots,
|
|
67
|
+
}))),
|
|
64
68
|
};
|
|
65
69
|
}
|
|
70
|
+
function collectProviderRefreshAdvice(collections) {
|
|
71
|
+
return collections.flatMap((collection) => {
|
|
72
|
+
const providerContext = collection.providerContext;
|
|
73
|
+
if (!providerContext)
|
|
74
|
+
return [];
|
|
75
|
+
const active = new Set(providerContext.activeProviders);
|
|
76
|
+
return providerContext.registrations.flatMap((registration) => {
|
|
77
|
+
if (!active.has(registration.adapter.name))
|
|
78
|
+
return [];
|
|
79
|
+
return registration.capabilities
|
|
80
|
+
.filter(({ scope, support }) => scope === collection.scope && support === 'supported')
|
|
81
|
+
.map((capability) => ({
|
|
82
|
+
scope: collection.scope,
|
|
83
|
+
provider: registration.adapter.name,
|
|
84
|
+
contentKind: capability.contentKind,
|
|
85
|
+
visibility: adviseProviderRefresh({
|
|
86
|
+
policy: capability.catalogRefresh,
|
|
87
|
+
materialization: 'unknown',
|
|
88
|
+
observation: {
|
|
89
|
+
state: 'not-reported',
|
|
90
|
+
reference: 'oat status inspects managed files but does not query the active provider catalog',
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
}));
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function formatProviderRefreshAdvice(advice) {
|
|
98
|
+
if (advice.length === 0)
|
|
99
|
+
return null;
|
|
100
|
+
return [
|
|
101
|
+
'Provider catalog visibility:',
|
|
102
|
+
...advice.map(({ scope, provider, contentKind, visibility }) => ` [${scope}] ${provider}/${contentKind}: ${visibility.state} (${visibility.policy.state})`),
|
|
103
|
+
].join('\n');
|
|
104
|
+
}
|
|
66
105
|
const DEFAULT_DEPENDENCIES = {
|
|
67
106
|
buildCommandContext,
|
|
68
107
|
async resolveScopeRoot(scope, context) {
|
|
@@ -80,15 +119,10 @@ const DEFAULT_DEPENDENCIES = {
|
|
|
80
119
|
scanCanonical,
|
|
81
120
|
scanBundledManagedAgents,
|
|
82
121
|
getAdapters() {
|
|
83
|
-
return
|
|
84
|
-
claudeAdapter,
|
|
85
|
-
cursorAdapter,
|
|
86
|
-
codexAdapter,
|
|
87
|
-
copilotAdapter,
|
|
88
|
-
geminiAdapter,
|
|
89
|
-
];
|
|
122
|
+
return getProviderRegistrations().map(({ adapter }) => adapter);
|
|
90
123
|
},
|
|
91
124
|
getConfigAwareAdapters,
|
|
125
|
+
resolveProviderScopeContext,
|
|
92
126
|
getSyncMappings,
|
|
93
127
|
getAdoptionSources,
|
|
94
128
|
detectDrift,
|
|
@@ -120,9 +154,6 @@ function canonicalInsideMapping(canonicalPath, mappingCanonicalDir) {
|
|
|
120
154
|
return (normalizedCanonicalPath === normalizedCanonicalDir ||
|
|
121
155
|
normalizedCanonicalPath.startsWith(`${normalizedCanonicalDir}/`));
|
|
122
156
|
}
|
|
123
|
-
function contentTypeAllowed(contentType, scope) {
|
|
124
|
-
return SCOPE_CONTENT_TYPES[scope].includes(contentType);
|
|
125
|
-
}
|
|
126
157
|
function summarizeReports(reports) {
|
|
127
158
|
const summary = {
|
|
128
159
|
total: reports.length,
|
|
@@ -243,7 +274,7 @@ function shouldReportPjmAdoption(adoption, states) {
|
|
|
243
274
|
const pjm = states.find(({ pack }) => pack === 'project-management');
|
|
244
275
|
return (pjm?.scopes ?? []).some(({ scope }) => scope === 'project');
|
|
245
276
|
}
|
|
246
|
-
async function collectPackReport(scopeRoots, unavailableScopes,
|
|
277
|
+
async function collectPackReport(scopeRoots, unavailableScopes, userAgentCoverage, dependencies) {
|
|
247
278
|
const roots = {
|
|
248
279
|
...(scopeRoots.has('project')
|
|
249
280
|
? { projectRoot: scopeRoots.get('project') }
|
|
@@ -256,6 +287,7 @@ async function collectPackReport(scopeRoots, unavailableScopes, userManagedRoleM
|
|
|
256
287
|
states: [],
|
|
257
288
|
unavailableScopes,
|
|
258
289
|
pjm: null,
|
|
290
|
+
evidence: packEvidenceBlock([]),
|
|
259
291
|
};
|
|
260
292
|
}
|
|
261
293
|
let inventories;
|
|
@@ -266,9 +298,23 @@ async function collectPackReport(scopeRoots, unavailableScopes, userManagedRoleM
|
|
|
266
298
|
assetsRoot,
|
|
267
299
|
...roots,
|
|
268
300
|
...(scopeRoots.has('user')
|
|
269
|
-
? {
|
|
301
|
+
? {
|
|
302
|
+
userManagedRoleMaterialization: userAgentCoverage !== 'none',
|
|
303
|
+
}
|
|
270
304
|
: {}),
|
|
271
305
|
}))));
|
|
306
|
+
if (userAgentCoverage === 'all') {
|
|
307
|
+
inventories = inventories.map((inventory) => ({
|
|
308
|
+
...inventory,
|
|
309
|
+
scopes: inventory.scopes.map((scoped) => scoped.scope === 'user'
|
|
310
|
+
? {
|
|
311
|
+
...scoped,
|
|
312
|
+
diagnostics: scoped.diagnostics.filter(({ code }) => code !== 'user-agent-unmaterialized'),
|
|
313
|
+
}
|
|
314
|
+
: scoped),
|
|
315
|
+
diagnostics: inventory.diagnostics.filter(({ code }) => code !== 'user-agent-unmaterialized'),
|
|
316
|
+
}));
|
|
317
|
+
}
|
|
272
318
|
}
|
|
273
319
|
catch (error) {
|
|
274
320
|
return unavailablePackReport(error, roots, unavailableScopes);
|
|
@@ -276,6 +322,7 @@ async function collectPackReport(scopeRoots, unavailableScopes, userManagedRoleM
|
|
|
276
322
|
const states = inventories
|
|
277
323
|
.map((inventory) => toStatusPackState(inventory, roots))
|
|
278
324
|
.filter((state) => state !== null);
|
|
325
|
+
const evidence = packEvidenceBlock(inventories.map((canonical) => projectRenderablePackEvidence(canonical, roots)));
|
|
279
326
|
const projectRoot = scopeRoots.get('project');
|
|
280
327
|
if (!projectRoot) {
|
|
281
328
|
return {
|
|
@@ -283,6 +330,7 @@ async function collectPackReport(scopeRoots, unavailableScopes, userManagedRoleM
|
|
|
283
330
|
states,
|
|
284
331
|
unavailableScopes,
|
|
285
332
|
pjm: null,
|
|
333
|
+
evidence,
|
|
286
334
|
};
|
|
287
335
|
}
|
|
288
336
|
const adoption = await dependencies.resolvePjmAdoption({
|
|
@@ -301,6 +349,7 @@ async function collectPackReport(scopeRoots, unavailableScopes, userManagedRoleM
|
|
|
301
349
|
repoRoot: formatPackPath(adoption.repoRoot, roots),
|
|
302
350
|
recovery: adoption.recovery,
|
|
303
351
|
},
|
|
352
|
+
evidence,
|
|
304
353
|
};
|
|
305
354
|
}
|
|
306
355
|
function describePackScope(state) {
|
|
@@ -375,29 +424,79 @@ async function collectScopeReports(scope, context, dependencies) {
|
|
|
375
424
|
const manifestPath = join(scopeRoot, '.oat', 'sync', 'manifest.json');
|
|
376
425
|
const syncConfigPath = join(scopeRoot, '.oat', 'sync', 'config.json');
|
|
377
426
|
const userConfigDir = join(context.home, '.oat');
|
|
378
|
-
const [manifest,
|
|
427
|
+
const [manifest, syncConfig, userSyncConfig] = await Promise.all([
|
|
379
428
|
dependencies.loadManifest(manifestPath),
|
|
380
|
-
dependencies.scanCanonical(scopeRoot, scope),
|
|
381
429
|
dependencies.loadSyncConfig(syncConfigPath),
|
|
382
430
|
dependencies.resolveUserSyncConfig(userConfigDir),
|
|
383
431
|
]);
|
|
384
|
-
const
|
|
385
|
-
const
|
|
432
|
+
const effectiveConfig = scope === 'user' ? userSyncConfig : syncConfig;
|
|
433
|
+
const providerContext = dependencies.resolveProviderScopeContext
|
|
434
|
+
? await dependencies.resolveProviderScopeContext({
|
|
435
|
+
scope,
|
|
436
|
+
scopeRoot,
|
|
437
|
+
config: effectiveConfig,
|
|
438
|
+
})
|
|
439
|
+
: null;
|
|
440
|
+
const adapters = providerContext
|
|
441
|
+
? providerContext.registrations.map(({ adapter }) => adapter)
|
|
442
|
+
: dependencies.getAdapters();
|
|
443
|
+
const activeAdapters = providerContext
|
|
444
|
+
? adapters.filter(({ name }) => providerContext.activeProviders.includes(name))
|
|
445
|
+
: await dependencies
|
|
446
|
+
.getConfigAwareAdapters(adapters, scopeRoot, effectiveConfig)
|
|
447
|
+
.then((resolution) => resolution.activeAdapters);
|
|
448
|
+
const activeAdapterNames = activeAdapters.map(({ name }) => name);
|
|
449
|
+
const knownRegistrations = getProviderRegistrations().filter(({ adapter }) => activeAdapterNames.includes(adapter.name));
|
|
450
|
+
const coverageRegistrations = providerContext?.registrations ?? knownRegistrations;
|
|
451
|
+
const mappingScanTargets = activeAdapters
|
|
452
|
+
.flatMap((adapter) => dependencies.getSyncMappings(adapter, scope))
|
|
453
|
+
.map(({ contentType, canonicalDir }) => ({ contentType, canonicalDir }));
|
|
454
|
+
const capabilityScanTargets = coverageRegistrations
|
|
455
|
+
.filter(({ adapter }) => activeAdapterNames.includes(adapter.name))
|
|
456
|
+
.flatMap(({ capabilities }) => capabilities
|
|
457
|
+
.filter((capability) => capability.scope === scope &&
|
|
458
|
+
capability.support === 'supported' &&
|
|
459
|
+
capability.contentKind !== 'directory')
|
|
460
|
+
.map((capability) => ({
|
|
461
|
+
contentType: capability.contentKind,
|
|
462
|
+
canonicalDir: `.agents/${capability.contentKind}s`,
|
|
463
|
+
})));
|
|
464
|
+
const scanTargets = [...mappingScanTargets, ...capabilityScanTargets].filter((target, index, targets) => targets.findIndex((candidate) => candidate.contentType === target.contentType &&
|
|
465
|
+
candidate.canonicalDir === target.canonicalDir) === index);
|
|
466
|
+
const canonicalEntries = await dependencies.scanCanonical(scopeRoot, scope, scanTargets);
|
|
467
|
+
let agentCoverage = userAgentMaterializationCoverage({
|
|
468
|
+
registrations: coverageRegistrations,
|
|
469
|
+
activeProviders: activeAdapterNames,
|
|
470
|
+
});
|
|
471
|
+
if (scope === 'user' && agentCoverage !== 'all') {
|
|
472
|
+
const activeAgentMappings = activeAdapters.flatMap((adapter) => dependencies
|
|
473
|
+
.getSyncMappings(adapter, scope)
|
|
474
|
+
.filter(({ contentType }) => contentType === 'agent'));
|
|
475
|
+
if (activeAgentMappings.some(({ nativeRead }) => !nativeRead)) {
|
|
476
|
+
agentCoverage = 'all';
|
|
477
|
+
}
|
|
478
|
+
else if (activeAgentMappings.length > 0 && agentCoverage === 'none') {
|
|
479
|
+
agentCoverage = 'bundled';
|
|
480
|
+
}
|
|
481
|
+
}
|
|
386
482
|
const reports = [];
|
|
387
483
|
const strayCandidates = [];
|
|
388
484
|
const trackedCanonicalByProvider = new Set(manifest.entries.map((entry) => `${entry.provider}|${normalizeToPosixPath(entry.canonicalPath)}`));
|
|
389
485
|
const activeProviderNames = new Set(activeAdapters.map((adapter) => adapter.name));
|
|
486
|
+
const activeExtensionProviders = new Set(providerContext
|
|
487
|
+
? providerContext.registrations
|
|
488
|
+
.filter(({ adapter }) => activeProviderNames.has(adapter.name))
|
|
489
|
+
.flatMap(({ extensions }) => extensions.map(({ provider }) => provider))
|
|
490
|
+
: [...activeProviderNames]);
|
|
390
491
|
const extensionCanonicalEntries = scope === 'user' &&
|
|
391
|
-
(
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
...(await dependencies.scanBundledManagedAgents()),
|
|
395
|
-
]
|
|
492
|
+
(activeExtensionProviders.has('codex') ||
|
|
493
|
+
activeExtensionProviders.has('cursor'))
|
|
494
|
+
? mergeUserScopeMaterializationEntries(canonicalEntries, await dependencies.scanBundledManagedAgents())
|
|
396
495
|
: canonicalEntries;
|
|
397
|
-
const codexExtensionPlan =
|
|
496
|
+
const codexExtensionPlan = activeExtensionProviders.has('codex')
|
|
398
497
|
? await dependencies.computeCodexProjectExtensionPlan(scopeRoot, extensionCanonicalEntries, undefined, { userConfigDir })
|
|
399
498
|
: undefined;
|
|
400
|
-
const cursorExtensionPlan =
|
|
499
|
+
const cursorExtensionPlan = activeExtensionProviders.has('cursor')
|
|
401
500
|
? await dependencies.computeCursorProjectExtensionPlan(scopeRoot, extensionCanonicalEntries, undefined, { userConfigDir })
|
|
402
501
|
: undefined;
|
|
403
502
|
const materializationPlans = [
|
|
@@ -429,9 +528,6 @@ async function collectScopeReports(scope, context, dependencies) {
|
|
|
429
528
|
if (!mappingContentTypes.has(entry.contentType)) {
|
|
430
529
|
continue;
|
|
431
530
|
}
|
|
432
|
-
if (!contentTypeAllowed(entry.contentType, scope)) {
|
|
433
|
-
continue;
|
|
434
|
-
}
|
|
435
531
|
const matchedMapping = mappings.find((mapping) => mapping.contentType === entry.contentType &&
|
|
436
532
|
entryInsideMapping(entry.providerPath, mapping.providerDir));
|
|
437
533
|
if (!matchedMapping) {
|
|
@@ -549,7 +645,9 @@ async function collectScopeReports(scope, context, dependencies) {
|
|
|
549
645
|
manifest,
|
|
550
646
|
reports: filtered.reports,
|
|
551
647
|
strayCandidates: filtered.candidates,
|
|
552
|
-
activeAdapterNames
|
|
648
|
+
activeAdapterNames,
|
|
649
|
+
userAgentMaterializationCoverage: scope === 'user' ? agentCoverage : 'none',
|
|
650
|
+
providerContext,
|
|
553
651
|
};
|
|
554
652
|
}
|
|
555
653
|
async function runStatusCommand(context, dependencies, options = {}) {
|
|
@@ -577,6 +675,7 @@ async function runStatusCommand(context, dependencies, options = {}) {
|
|
|
577
675
|
scopeRoots.set(scope, scopeReportCollection.scopeRoot);
|
|
578
676
|
}
|
|
579
677
|
const summary = summarizeReports(reports);
|
|
678
|
+
const providerRefreshAdvice = collectProviderRefreshAdvice(scopeCollections);
|
|
580
679
|
const hasIssues = summary.total > 0 && summary.inSync !== summary.total;
|
|
581
680
|
if (options.hook) {
|
|
582
681
|
if (summary.drifted > 0 || summary.missing > 0) {
|
|
@@ -592,14 +691,19 @@ async function runStatusCommand(context, dependencies, options = {}) {
|
|
|
592
691
|
}
|
|
593
692
|
return;
|
|
594
693
|
}
|
|
595
|
-
const packReport = await collectPackReport(scopeRoots, unavailableScopes, scopeCollections.some((
|
|
596
|
-
|
|
694
|
+
const packReport = await collectPackReport(scopeRoots, unavailableScopes, scopeCollections.some((collection) => collection.userAgentMaterializationCoverage === 'all')
|
|
695
|
+
? 'all'
|
|
696
|
+
: scopeCollections.some((collection) => collection.userAgentMaterializationCoverage === 'bundled')
|
|
697
|
+
? 'bundled'
|
|
698
|
+
: 'none', dependencies);
|
|
597
699
|
if (context.json) {
|
|
598
700
|
const payload = {
|
|
599
701
|
scope: context.scope,
|
|
600
702
|
reports,
|
|
601
703
|
summary,
|
|
602
704
|
packs: packReport,
|
|
705
|
+
packEvidence: packReport.evidence,
|
|
706
|
+
providerRefreshAdvice,
|
|
603
707
|
};
|
|
604
708
|
if (!context.interactive && summary.stray > 0) {
|
|
605
709
|
payload.remediation = DEFAULT_REMEDIATION;
|
|
@@ -612,6 +716,9 @@ async function runStatusCommand(context, dependencies, options = {}) {
|
|
|
612
716
|
if (packSummary) {
|
|
613
717
|
context.logger.info(packSummary);
|
|
614
718
|
}
|
|
719
|
+
const providerSummary = formatProviderRefreshAdvice(providerRefreshAdvice);
|
|
720
|
+
if (providerSummary)
|
|
721
|
+
context.logger.info(providerSummary);
|
|
615
722
|
}
|
|
616
723
|
if (summary.stray > 0) {
|
|
617
724
|
if (context.interactive) {
|
|
@@ -758,6 +865,11 @@ export function createStatusCommand(overrides = {}) {
|
|
|
758
865
|
...DEFAULT_DEPENDENCIES,
|
|
759
866
|
...overrides,
|
|
760
867
|
};
|
|
868
|
+
if (overrides.resolveProviderScopeContext === undefined &&
|
|
869
|
+
(overrides.getAdapters !== undefined ||
|
|
870
|
+
overrides.getConfigAwareAdapters !== undefined)) {
|
|
871
|
+
dependencies.resolveProviderScopeContext = undefined;
|
|
872
|
+
}
|
|
761
873
|
return withScopeOption(new Command('status'))
|
|
762
874
|
.description('Report provider sync and drift status')
|
|
763
875
|
.option('--hook', 'Emit a minimal pre-commit message: warn on managed drift, info on strays')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/commands/sync/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAiB3D,OAAO,KAAK,EACV,aAAa,EACb,uBAAuB,EAExB,MAAM,cAAc,CAAC;AA2TtB,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,UAAU,EAAE,aAAa,EAAE,EAC3B,YAAY,EAAE,uBAAuB,GACpC,OAAO,CAAC,IAAI,CAAC,CA4Kf"}
|
|
@@ -1,24 +1,161 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { getProviderRegistrations, } from '../../providers/shared/registry.js';
|
|
2
|
+
import { adviseProviderRefresh, } from '../../providers/shared/restart-adviser.js';
|
|
3
|
+
import { buildCollectionLifecycle, countPlannedOperations, formatCollectionLifecycle, toSyncOutputPlan, } from './sync.utils.js';
|
|
4
|
+
function extensionResultContentKind(registrations, result) {
|
|
5
|
+
const registration = registrations.find(({ adapter }) => adapter.name === result.provider);
|
|
6
|
+
const candidates = registration?.capabilities.filter(({ scope, support, projectionModes }) => scope === result.scope &&
|
|
7
|
+
support === 'supported' &&
|
|
8
|
+
projectionModes.includes('materialization-extension'));
|
|
9
|
+
// Extension operation identities do not carry a canonical asset kind.
|
|
10
|
+
// Attribute only when provider capability evidence gives one unambiguous
|
|
11
|
+
// content kind; otherwise leave the exact result unattributed.
|
|
12
|
+
return candidates?.length === 1 ? candidates[0].contentKind : undefined;
|
|
13
|
+
}
|
|
14
|
+
function buildProviderRefreshAdvice(input) {
|
|
15
|
+
const registrations = getProviderRegistrations();
|
|
16
|
+
const changed = [
|
|
17
|
+
...input.operationResults
|
|
18
|
+
.filter(({ status }) => status === 'changed')
|
|
19
|
+
.map(({ scope, provider, contentKind }) => ({
|
|
20
|
+
scope,
|
|
21
|
+
provider,
|
|
22
|
+
contentKind,
|
|
23
|
+
})),
|
|
24
|
+
...input.extensionResults
|
|
25
|
+
.filter(({ status }) => status === 'changed')
|
|
26
|
+
.flatMap((result) => {
|
|
27
|
+
const contentKind = extensionResultContentKind(registrations, result);
|
|
28
|
+
return contentKind === undefined
|
|
29
|
+
? []
|
|
30
|
+
: [{ scope: result.scope, provider: result.provider, contentKind }];
|
|
31
|
+
}),
|
|
32
|
+
];
|
|
33
|
+
const seen = new Set();
|
|
34
|
+
return changed.flatMap(({ scope, provider, contentKind }) => {
|
|
35
|
+
const key = `${scope}:${provider}:${contentKind}`;
|
|
36
|
+
if (seen.has(key))
|
|
37
|
+
return [];
|
|
38
|
+
seen.add(key);
|
|
39
|
+
const policy = registrations
|
|
40
|
+
.find(({ adapter }) => adapter.name === provider)
|
|
41
|
+
?.capabilities.find((capability) => capability.scope === scope && capability.contentKind === contentKind)?.catalogRefresh ?? {
|
|
42
|
+
state: 'unknown',
|
|
43
|
+
reason: 'Provider or capability is not registered',
|
|
44
|
+
};
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
scope,
|
|
48
|
+
provider,
|
|
49
|
+
contentKind,
|
|
50
|
+
materialization: 'changed',
|
|
51
|
+
visibility: adviseProviderRefresh({
|
|
52
|
+
policy,
|
|
53
|
+
materialization: 'changed',
|
|
54
|
+
}),
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function formatProviderRefreshAdvice(advice) {
|
|
60
|
+
return advice
|
|
61
|
+
.map(({ scope, provider, contentKind, visibility }) => {
|
|
62
|
+
const recovery = visibility.recovery[0]?.message;
|
|
63
|
+
return `Provider visibility [${scope}] ${provider}/${contentKind}: ${visibility.state} — ${recovery ?? visibility.reason}`;
|
|
64
|
+
})
|
|
65
|
+
.join('\n');
|
|
66
|
+
}
|
|
67
|
+
function countSkippedExtensionEntries(scopePlans) {
|
|
3
68
|
return scopePlans.reduce((total, scopePlan) => {
|
|
4
69
|
const extensionSkipped = scopePlan.materializationExtensions.reduce((count, extension) => count +
|
|
5
70
|
extension.operations.filter((operation) => operation.action === 'skip')
|
|
6
71
|
.length, 0);
|
|
7
|
-
return
|
|
8
|
-
scopePlan.plan.entries.filter((entry) => entry.operation === 'skip')
|
|
9
|
-
.length +
|
|
10
|
-
extensionSkipped);
|
|
72
|
+
return total + extensionSkipped;
|
|
11
73
|
}, 0);
|
|
12
74
|
}
|
|
13
|
-
function buildSummary(scopePlans,
|
|
75
|
+
function buildSummary(scopePlans, coreApplied, coreFailed, coreSkipped, extensionApplied, extensionFailed) {
|
|
14
76
|
return {
|
|
15
77
|
plannedOperations: countPlannedOperations(scopePlans),
|
|
16
|
-
applied,
|
|
17
|
-
failed,
|
|
18
|
-
skipped:
|
|
78
|
+
applied: coreApplied + extensionApplied,
|
|
79
|
+
failed: coreFailed + extensionFailed,
|
|
80
|
+
skipped: coreSkipped + countSkippedExtensionEntries(scopePlans),
|
|
19
81
|
};
|
|
20
82
|
}
|
|
21
|
-
function
|
|
83
|
+
function normalizeOperationResults(plan, result) {
|
|
84
|
+
if (result.operations) {
|
|
85
|
+
return result.operations;
|
|
86
|
+
}
|
|
87
|
+
const plannedOperations = [...plan.entries, ...plan.removals];
|
|
88
|
+
return plannedOperations.map((operation) => {
|
|
89
|
+
return {
|
|
90
|
+
scope: plan.scope,
|
|
91
|
+
provider: operation.provider,
|
|
92
|
+
contentKind: operation.canonical.type,
|
|
93
|
+
asset: operation.canonical.name,
|
|
94
|
+
action: operation.operation,
|
|
95
|
+
status: operation.operation === 'skip' ? 'current' : 'unknown',
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function materializationOperationIdentity(operation) {
|
|
100
|
+
return JSON.stringify([
|
|
101
|
+
operation.provider,
|
|
102
|
+
operation.target,
|
|
103
|
+
operation.path,
|
|
104
|
+
operation.action,
|
|
105
|
+
operation.entryName ?? null,
|
|
106
|
+
]);
|
|
107
|
+
}
|
|
108
|
+
function syncOperationIdentity(operation) {
|
|
109
|
+
return JSON.stringify([
|
|
110
|
+
operation.scope,
|
|
111
|
+
operation.provider,
|
|
112
|
+
operation.contentKind,
|
|
113
|
+
operation.asset,
|
|
114
|
+
operation.action,
|
|
115
|
+
]);
|
|
116
|
+
}
|
|
117
|
+
function coreHumanStatus(status) {
|
|
118
|
+
switch (status) {
|
|
119
|
+
case 'changed':
|
|
120
|
+
case 'current':
|
|
121
|
+
case 'failed':
|
|
122
|
+
case 'missing':
|
|
123
|
+
case 'unknown':
|
|
124
|
+
return status;
|
|
125
|
+
default:
|
|
126
|
+
return 'unknown';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function formatCoreResults(plan, evidence, dependencies) {
|
|
130
|
+
const operations = [...plan.entries, ...plan.removals];
|
|
131
|
+
if (operations.length === 0) {
|
|
132
|
+
if ((plan.collections?.length ?? 0) > 0) {
|
|
133
|
+
return 'Core results\nNo per-entry operations.';
|
|
134
|
+
}
|
|
135
|
+
return dependencies.formatSyncPlan(plan, true);
|
|
136
|
+
}
|
|
137
|
+
const resultsByIdentity = new Map((evidence?.operationResults ?? []).map((result) => [
|
|
138
|
+
syncOperationIdentity(result),
|
|
139
|
+
result,
|
|
140
|
+
]));
|
|
141
|
+
const lines = operations.map((operation) => {
|
|
142
|
+
const result = resultsByIdentity.get(syncOperationIdentity({
|
|
143
|
+
scope: plan.scope,
|
|
144
|
+
provider: operation.provider,
|
|
145
|
+
contentKind: operation.canonical.type,
|
|
146
|
+
asset: operation.canonical.name,
|
|
147
|
+
action: operation.operation,
|
|
148
|
+
}));
|
|
149
|
+
const status = coreHumanStatus(result?.status);
|
|
150
|
+
const failure = result?.failure ? ` — ${result.failure}` : '';
|
|
151
|
+
return `- ${plan.scope}:${operation.provider}:${operation.canonical.type}:${operation.operation} ${operation.canonical.name}\n reason: ${operation.reason}\n result: ${status}${failure}`;
|
|
152
|
+
});
|
|
153
|
+
const aggregate = evidence?.aggregateOnly
|
|
154
|
+
? `\nCore aggregate result: applied ${evidence.aggregate.applied}, failed ${evidence.aggregate.failed}, skipped ${evidence.aggregate.skipped}; non-skip named outcomes remain unknown.`
|
|
155
|
+
: '';
|
|
156
|
+
return `Core results${aggregate}\n${lines.join('\n')}`;
|
|
157
|
+
}
|
|
158
|
+
function formatAppliedOutput(scopePlans, coreApplyEvidence, dependencies) {
|
|
22
159
|
if (scopePlans.length === 0) {
|
|
23
160
|
return dependencies.formatSyncPlan({
|
|
24
161
|
scope: 'project',
|
|
@@ -28,28 +165,53 @@ function formatAppliedOutput(scopePlans, dependencies) {
|
|
|
28
165
|
}
|
|
29
166
|
return scopePlans
|
|
30
167
|
.map((scopePlan) => {
|
|
31
|
-
const syncOutput =
|
|
168
|
+
const syncOutput = formatCoreResults(scopePlan.plan, coreApplyEvidence.find((evidence) => evidence.plan === scopePlan.plan), dependencies);
|
|
169
|
+
const collectionOutput = formatCollectionLifecycle(buildCollectionLifecycle(scopePlan, coreApplyEvidence.find((evidence) => evidence.plan === scopePlan.plan)
|
|
170
|
+
?.collectionResults));
|
|
32
171
|
if (scopePlan.materializationExtensions.length === 0) {
|
|
33
|
-
return `Scope: ${scopePlan.scope}\n${syncOutput}
|
|
172
|
+
return [`Scope: ${scopePlan.scope}\n${syncOutput}`, collectionOutput]
|
|
173
|
+
.filter(Boolean)
|
|
174
|
+
.join('\n\n');
|
|
34
175
|
}
|
|
35
176
|
const extensionSections = scopePlan.materializationExtensions.map((extension) => {
|
|
177
|
+
const resultsByIdentity = new Map((extension.operationResults ?? []).map((result) => [
|
|
178
|
+
materializationOperationIdentity(result),
|
|
179
|
+
result,
|
|
180
|
+
]));
|
|
36
181
|
const lines = extension.operations.map((operation) => {
|
|
37
182
|
const entry = operation.entryName
|
|
38
183
|
? ` (${operation.entryName})`
|
|
39
184
|
: '';
|
|
40
|
-
|
|
185
|
+
const result = resultsByIdentity.get(materializationOperationIdentity(operation));
|
|
186
|
+
const status = result?.status ?? 'unknown';
|
|
187
|
+
const failure = result?.failure ? ` — ${result.failure}` : '';
|
|
188
|
+
return `- ${operation.provider}:${operation.target}:${operation.action} ${operation.path}${entry}\n reason: ${operation.reason}\n result: ${status}${failure}`;
|
|
41
189
|
});
|
|
42
|
-
return `${extension.provider} extension
|
|
190
|
+
return `${extension.provider} extension results\n${lines.join('\n')}`;
|
|
43
191
|
});
|
|
44
|
-
return
|
|
192
|
+
return [
|
|
193
|
+
`Scope: ${scopePlan.scope}\n${syncOutput}`,
|
|
194
|
+
collectionOutput,
|
|
195
|
+
extensionSections.join('\n\n'),
|
|
196
|
+
]
|
|
197
|
+
.filter(Boolean)
|
|
198
|
+
.join('\n\n');
|
|
45
199
|
})
|
|
46
200
|
.join('\n\n');
|
|
47
201
|
}
|
|
48
202
|
export async function runSyncApply(context, scopePlans, dependencies) {
|
|
49
|
-
let
|
|
50
|
-
let
|
|
203
|
+
let extensionApplied = 0;
|
|
204
|
+
let extensionFailed = 0;
|
|
205
|
+
let coreApplied = 0;
|
|
206
|
+
let coreFailed = 0;
|
|
207
|
+
let coreSkipped = 0;
|
|
208
|
+
const operationResults = [];
|
|
209
|
+
const coreApplyEvidence = [];
|
|
210
|
+
const extensionOperationResults = [];
|
|
51
211
|
for (const scopePlan of scopePlans) {
|
|
52
|
-
const hasSyncEntries = scopePlan.plan.entries.length > 0 ||
|
|
212
|
+
const hasSyncEntries = scopePlan.plan.entries.length > 0 ||
|
|
213
|
+
scopePlan.plan.removals.length > 0 ||
|
|
214
|
+
(scopePlan.plan.collections?.length ?? 0) > 0;
|
|
53
215
|
const hasExtensionPlannedOperations = scopePlan.materializationExtensionPlans.some((plan) => plan.operations.some((operation) => operation.action !== 'skip'));
|
|
54
216
|
// Derived from the same diagnostic that produced the pre-mutation advisory
|
|
55
217
|
// (`detectVersionSkew` in ./index), so the restamp and the warning cannot
|
|
@@ -63,8 +225,18 @@ export async function runSyncApply(context, scopePlans, dependencies) {
|
|
|
63
225
|
}
|
|
64
226
|
if (hasSyncEntries || shouldRefreshManifestVersion) {
|
|
65
227
|
const result = await dependencies.executeSyncPlan(scopePlan.plan, scopePlan.manifest, scopePlan.manifestPath);
|
|
66
|
-
|
|
67
|
-
|
|
228
|
+
coreApplied += result.applied;
|
|
229
|
+
coreFailed += result.failed;
|
|
230
|
+
coreSkipped += result.skipped;
|
|
231
|
+
const normalizedResults = normalizeOperationResults(scopePlan.plan, result);
|
|
232
|
+
operationResults.push(...normalizedResults);
|
|
233
|
+
coreApplyEvidence.push({
|
|
234
|
+
plan: scopePlan.plan,
|
|
235
|
+
operationResults: normalizedResults,
|
|
236
|
+
aggregateOnly: result.operations === undefined,
|
|
237
|
+
aggregate: result,
|
|
238
|
+
collectionResults: result.collectionResults ?? [],
|
|
239
|
+
});
|
|
68
240
|
}
|
|
69
241
|
for (const plan of scopePlan.materializationExtensionPlans) {
|
|
70
242
|
if (!plan.operations.some((operation) => operation.action !== 'skip')) {
|
|
@@ -77,15 +249,22 @@ export async function runSyncApply(context, scopePlans, dependencies) {
|
|
|
77
249
|
throw new Error(`Materialization extension ${plan.provider} disappeared before apply.`);
|
|
78
250
|
}
|
|
79
251
|
const result = await dependencies.applyMaterializationExtensionPlan(extension, scopePlan.scopeRoot, plan);
|
|
80
|
-
|
|
81
|
-
|
|
252
|
+
extensionApplied += result.applied;
|
|
253
|
+
extensionFailed += result.failed;
|
|
254
|
+
extensionOperationResults.push(...(result.operations ?? []).map((operation) => ({
|
|
255
|
+
...operation,
|
|
256
|
+
scope: scopePlan.scope,
|
|
257
|
+
})));
|
|
82
258
|
const summary = scopePlan.materializationExtensions.find((candidate) => candidate.provider === plan.provider);
|
|
83
259
|
if (summary) {
|
|
84
|
-
|
|
260
|
+
summary.applied = result.applied;
|
|
261
|
+
summary.failed = result.failed;
|
|
262
|
+
summary.skipped = result.skipped;
|
|
263
|
+
summary.operationResults = result.operations;
|
|
85
264
|
}
|
|
86
265
|
}
|
|
87
266
|
}
|
|
88
|
-
const summary = buildSummary(scopePlans,
|
|
267
|
+
const summary = buildSummary(scopePlans, coreApplied, coreFailed, coreSkipped, extensionApplied, extensionFailed);
|
|
89
268
|
const providerMismatches = scopePlans
|
|
90
269
|
.map((scopePlan) => scopePlan.providerMismatches)
|
|
91
270
|
.filter((mismatch) => mismatch !== undefined);
|
|
@@ -109,29 +288,41 @@ export async function runSyncApply(context, scopePlans, dependencies) {
|
|
|
109
288
|
failed: extension.failed,
|
|
110
289
|
skipped: extension.skipped,
|
|
111
290
|
}));
|
|
291
|
+
const providerRefreshAdvice = buildProviderRefreshAdvice({
|
|
292
|
+
operationResults,
|
|
293
|
+
extensionResults: extensionOperationResults,
|
|
294
|
+
});
|
|
295
|
+
const collectionOperations = scopePlans.flatMap((scopePlan) => buildCollectionLifecycle(scopePlan, coreApplyEvidence.find((evidence) => evidence.plan === scopePlan.plan)
|
|
296
|
+
?.collectionResults));
|
|
112
297
|
if (context.json) {
|
|
113
298
|
context.logger.json({
|
|
114
299
|
scope: context.scope,
|
|
115
300
|
dryRun: false,
|
|
116
|
-
plans: scopePlans.map(
|
|
301
|
+
plans: scopePlans.map(toSyncOutputPlan),
|
|
302
|
+
collectionOperations,
|
|
117
303
|
summary,
|
|
118
304
|
providerMismatches,
|
|
119
305
|
versionSkew,
|
|
120
306
|
materializationExtensions,
|
|
307
|
+
operationResults,
|
|
121
308
|
codexExtensions,
|
|
309
|
+
providerRefreshAdvice,
|
|
122
310
|
});
|
|
123
311
|
}
|
|
124
312
|
else {
|
|
125
|
-
context.logger.info(formatAppliedOutput(scopePlans, dependencies));
|
|
313
|
+
context.logger.info(formatAppliedOutput(scopePlans, coreApplyEvidence, dependencies));
|
|
126
314
|
if (summary.plannedOperations === 0) {
|
|
127
315
|
context.logger.info('\nNo changes required.');
|
|
128
316
|
}
|
|
129
|
-
else if (failed > 0) {
|
|
317
|
+
else if (summary.failed > 0) {
|
|
130
318
|
context.logger.warn('\nSync completed with partial failures.');
|
|
131
319
|
}
|
|
132
320
|
else {
|
|
133
321
|
context.logger.success('\nSync applied successfully.');
|
|
134
322
|
}
|
|
323
|
+
if (providerRefreshAdvice.length > 0) {
|
|
324
|
+
context.logger.info(`\n${formatProviderRefreshAdvice(providerRefreshAdvice)}`);
|
|
325
|
+
}
|
|
135
326
|
}
|
|
136
|
-
process.exitCode = failed > 0 ? 1 : 0;
|
|
327
|
+
process.exitCode = summary.failed > 0 ? 1 : 0;
|
|
137
328
|
}
|