@open-agent-toolkit/cli 0.2.62 → 0.2.64
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/config-and-local-state.md +1 -0
- package/assets/docs/cli-utilities/configuration.md +10 -8
- package/assets/docs/cli-utilities/project-log.md +16 -0
- package/assets/docs/cli-utilities/tool-packs.md +83 -0
- package/assets/docs/cli-utilities/workflow-gates.md +124 -16
- package/assets/docs/contributing/skills.md +42 -7
- package/assets/docs/provider-sync/commands.md +3 -0
- package/assets/docs/provider-sync/instruction-sync.md +107 -0
- package/assets/docs/provider-sync/manifest-and-drift.md +105 -0
- package/assets/docs/reference/cli-reference.md +16 -6
- package/assets/docs/reference/oat-directory-structure.md +32 -31
- package/assets/docs/workflows/projects/lifecycle.md +45 -0
- package/assets/docs/workflows/projects/picking-up-projects.md +14 -0
- package/assets/docs/workflows/skills/explainer-kit.md +10 -4
- package/assets/docs/workflows/skills/repo-improve.md +15 -1
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/create-agnostic-skill/SKILL.md +9 -7
- package/assets/skills/create-agnostic-skill/references/skill-template.md +9 -7
- package/assets/skills/oat-explainer-kit/SKILL.md +14 -1
- package/assets/skills/oat-explainer-kit/references/config-contract.md +12 -0
- package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +57 -10
- package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +28 -5
- package/assets/skills/oat-explainer-kit/scripts/probe-recap-seams.mjs +371 -0
- package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +123 -1
- package/assets/skills/oat-project-autonomous/SKILL.md +10 -1
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +122 -121
- package/assets/skills/oat-project-complete/SKILL.md +134 -4
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-implement/SKILL.md +1 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +38 -6
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-next/SKILL.md +62 -19
- package/assets/skills/oat-project-plan/SKILL.md +31 -5
- package/assets/skills/oat-project-pr-final/SKILL.md +281 -6
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-progress/SKILL.md +12 -3
- package/assets/skills/oat-project-quick-start/SKILL.md +264 -4
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +122 -121
- package/assets/skills/oat-project-summary/SKILL.md +34 -23
- package/assets/skills/oat-repo-improve/SKILL.md +40 -5
- package/assets/skills/oat-repo-improve/references/plan-template.md +84 -7
- package/dist/agents/canonical/resolve.d.ts.map +1 -1
- package/dist/agents/canonical/resolve.js +25 -4
- package/dist/commands/config/index.d.ts +1 -0
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +401 -18
- package/dist/commands/doctor/index.d.ts +7 -0
- package/dist/commands/doctor/index.d.ts.map +1 -1
- package/dist/commands/doctor/index.js +10 -2
- package/dist/commands/gate/index.d.ts +3 -1
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +699 -211
- package/dist/commands/init/tools/index.d.ts.map +1 -1
- package/dist/commands/init/tools/index.js +68 -36
- package/dist/commands/init/tools/shared/skill-script-references.d.ts +126 -0
- package/dist/commands/init/tools/shared/skill-script-references.d.ts.map +1 -0
- package/dist/commands/init/tools/shared/skill-script-references.js +311 -0
- package/dist/commands/instructions/instructions.types.d.ts +63 -0
- package/dist/commands/instructions/instructions.types.d.ts.map +1 -1
- package/dist/commands/instructions/instructions.utils.d.ts +51 -2
- package/dist/commands/instructions/instructions.utils.d.ts.map +1 -1
- package/dist/commands/instructions/instructions.utils.js +201 -4
- package/dist/commands/instructions/sync/sync.d.ts.map +1 -1
- package/dist/commands/instructions/sync/sync.js +12 -1
- package/dist/commands/instructions/validate/validate.d.ts.map +1 -1
- package/dist/commands/instructions/validate/validate.js +12 -1
- package/dist/commands/project/log/append.d.ts +195 -0
- package/dist/commands/project/log/append.d.ts.map +1 -1
- package/dist/commands/project/log/append.js +1034 -11
- package/dist/commands/shared/frontmatter.d.ts +51 -0
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +118 -6
- package/dist/commands/status/index.d.ts.map +1 -1
- package/dist/commands/status/index.js +5 -3
- package/dist/commands/sync/index.d.ts +14 -0
- package/dist/commands/sync/index.d.ts.map +1 -1
- package/dist/commands/sync/index.js +21 -0
- package/dist/commands/tools/info/index.d.ts.map +1 -1
- package/dist/commands/tools/info/index.js +14 -1
- package/dist/commands/tools/info/info-tool.d.ts +12 -0
- package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
- package/dist/commands/tools/info/info-tool.js +54 -6
- package/dist/commands/tools/info/skill-views.d.ts +86 -0
- package/dist/commands/tools/info/skill-views.d.ts.map +1 -0
- package/dist/commands/tools/info/skill-views.js +383 -0
- package/dist/commands/tools/install/index.d.ts.map +1 -1
- package/dist/commands/tools/install/index.js +3 -25
- 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 +23 -4
- package/dist/commands/tools/remove/index.d.ts.map +1 -1
- package/dist/commands/tools/remove/index.js +35 -42
- package/dist/commands/tools/remove/remove-tools.d.ts +3 -2
- package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
- package/dist/commands/tools/remove/remove-tools.js +14 -4
- package/dist/commands/tools/shared/auto-sync.d.ts +12 -1
- package/dist/commands/tools/shared/auto-sync.d.ts.map +1 -1
- package/dist/commands/tools/shared/auto-sync.js +20 -4
- package/dist/commands/tools/shared/format-pack-inventory.d.ts +12 -1
- package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -1
- package/dist/commands/tools/shared/format-pack-inventory.js +48 -6
- package/dist/commands/tools/shared/in-process-sync.d.ts +11 -0
- package/dist/commands/tools/shared/in-process-sync.d.ts.map +1 -0
- package/dist/commands/tools/shared/in-process-sync.js +79 -0
- package/dist/commands/tools/shared/pack-evidence.d.ts +78 -2
- package/dist/commands/tools/shared/pack-evidence.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-evidence.js +96 -2
- package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts +11 -0
- package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-lifecycle-outcome.js +24 -3
- package/dist/commands/tools/shared/pack-provider-evidence.d.ts +73 -0
- package/dist/commands/tools/shared/pack-provider-evidence.d.ts.map +1 -0
- package/dist/commands/tools/shared/pack-provider-evidence.js +161 -0
- package/dist/commands/tools/shared/provider-context.d.ts +88 -0
- package/dist/commands/tools/shared/provider-context.d.ts.map +1 -0
- package/dist/commands/tools/shared/provider-context.js +77 -0
- package/dist/commands/tools/shared/provider-reachability.d.ts +93 -0
- package/dist/commands/tools/shared/provider-reachability.d.ts.map +1 -0
- package/dist/commands/tools/shared/provider-reachability.js +358 -0
- package/dist/commands/tools/shared/sync-evidence.d.ts +57 -0
- package/dist/commands/tools/shared/sync-evidence.d.ts.map +1 -0
- package/dist/commands/tools/shared/sync-evidence.js +147 -0
- package/dist/commands/tools/update/index.d.ts +0 -4
- package/dist/commands/tools/update/index.d.ts.map +1 -1
- package/dist/commands/tools/update/index.js +22 -40
- package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
- package/dist/commands/tools/update/update-tools.js +23 -8
- package/dist/config/json.d.ts +36 -0
- package/dist/config/json.d.ts.map +1 -1
- package/dist/config/json.js +135 -3
- 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 +111 -0
- package/dist/drift/index.d.ts +2 -0
- package/dist/drift/index.d.ts.map +1 -1
- package/dist/drift/index.js +1 -0
- package/dist/drift/skill-view-diagnostic.d.ts +197 -0
- package/dist/drift/skill-view-diagnostic.d.ts.map +1 -0
- package/dist/drift/skill-view-diagnostic.js +343 -0
- package/dist/validation/skills.d.ts +1 -0
- package/dist/validation/skills.d.ts.map +1 -1
- package/dist/validation/skills.js +181 -19
- package/package.json +2 -2
|
@@ -35,10 +35,67 @@ export interface InstructionsJsonPayload {
|
|
|
35
35
|
summary: InstructionsSummary;
|
|
36
36
|
entries: InstructionEntry[];
|
|
37
37
|
actions: InstructionActionRecord[];
|
|
38
|
+
/**
|
|
39
|
+
* The normalized repo-relative exclusions this scan was *configured* with, in
|
|
40
|
+
* resolution order. An entry here is a statement of intent, not a guarantee:
|
|
41
|
+
* it may name a directory that does not exist, differ in case from the real
|
|
42
|
+
* path on a case-insensitive filesystem, or be shadowed by the `.oat/repo`
|
|
43
|
+
* carve-in.
|
|
44
|
+
*
|
|
45
|
+
* Read `effectiveExcludedPaths` to learn what was actually protected.
|
|
46
|
+
*
|
|
47
|
+
* Additive and omitted entirely when nothing was configured, so payloads from
|
|
48
|
+
* repositories without a documentation root are byte-identical to the
|
|
49
|
+
* pre-exclusion shape.
|
|
50
|
+
*/
|
|
51
|
+
excludedPaths?: string[];
|
|
52
|
+
/**
|
|
53
|
+
* The subset of `excludedPaths` that names a real, case-exact directory the
|
|
54
|
+
* scan can actually prune. This is the field a consumer should trust when
|
|
55
|
+
* deciding whether a tree is protected; every configured entry missing from
|
|
56
|
+
* it was also reported as a warning on stderr.
|
|
57
|
+
*
|
|
58
|
+
* Present whenever `excludedPaths` is, including as an empty array when every
|
|
59
|
+
* configured entry turned out to be inert; omitted only when nothing was
|
|
60
|
+
* configured at all.
|
|
61
|
+
*/
|
|
62
|
+
effectiveExcludedPaths?: string[];
|
|
63
|
+
/**
|
|
64
|
+
* One message per configured exclusion that will not protect anything, the
|
|
65
|
+
* same text written to stderr in human mode.
|
|
66
|
+
*
|
|
67
|
+
* This field is why the JSON surface is complete. `logger.warn` is suppressed
|
|
68
|
+
* under `--json`, and an entry rejected during normalization (an absolute
|
|
69
|
+
* path, or one escaping the repository) never reaches `excludedPaths` either
|
|
70
|
+
* — so without this a `--json` consumer would see no trace at all of an
|
|
71
|
+
* exclusion that silently does nothing. Omitted when empty.
|
|
72
|
+
*/
|
|
73
|
+
exclusionWarnings?: string[];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The resolved exclusion set, split so that intent and effect cannot be
|
|
77
|
+
* confused. A configured entry that protects nothing is the failure mode this
|
|
78
|
+
* split exists to surface: silently reporting it as applied would let an
|
|
79
|
+
* operator believe a documentation tree is safe while pointers are written
|
|
80
|
+
* into it.
|
|
81
|
+
*/
|
|
82
|
+
export interface InstructionPointerExclusions {
|
|
83
|
+
/** Normalized entries exactly as configured, in resolution order. */
|
|
84
|
+
configured: string[];
|
|
85
|
+
/** The subset that names a real, case-exact, prunable directory. */
|
|
86
|
+
effective: string[];
|
|
87
|
+
/** One human-readable warning per configured entry that will do nothing. */
|
|
88
|
+
warnings: string[];
|
|
38
89
|
}
|
|
39
90
|
export interface InstructionsScanOptions {
|
|
40
91
|
strategy?: InstructionSyncStrategy;
|
|
41
92
|
debug?: (message: string) => void;
|
|
93
|
+
/**
|
|
94
|
+
* Repo-root-relative directories whose subtrees are left out of the scan.
|
|
95
|
+
* Applied after the excluded-root carve-in, so excluding a directory can
|
|
96
|
+
* never strand a subtree the carve-in re-entered (`.oat/repo/**`).
|
|
97
|
+
*/
|
|
98
|
+
excludedPaths?: string[];
|
|
42
99
|
}
|
|
43
100
|
export interface InstructionsScanDependencies {
|
|
44
101
|
readdir: (path: string, options: {
|
|
@@ -53,6 +110,12 @@ export interface InstructionsScanDependencies {
|
|
|
53
110
|
export interface InstructionsValidateCommandDependencies {
|
|
54
111
|
buildCommandContext: (options: GlobalOptions) => CommandContext;
|
|
55
112
|
resolveProjectRoot: (cwd: string) => Promise<string>;
|
|
113
|
+
/**
|
|
114
|
+
* The single exclusion path both commands resolve through. Sync inherits it
|
|
115
|
+
* from this interface rather than resolving its own, so validate can never
|
|
116
|
+
* report drift that sync would refuse to fix.
|
|
117
|
+
*/
|
|
118
|
+
resolveInstructionPointerExcludes: (repoRoot: string) => Promise<InstructionPointerExclusions>;
|
|
56
119
|
scanInstructionFiles: (repoRoot: string, options?: InstructionsScanOptions, overrides?: Partial<InstructionsScanDependencies>) => Promise<InstructionEntry[]>;
|
|
57
120
|
}
|
|
58
121
|
export interface InstructionsSyncCommandDependencies extends InstructionsValidateCommandDependencies {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.types.d.ts","sourceRoot":"","sources":["../../../src/commands/instructions/instructions.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1E,eAAO,MAAM,2BAA2B,YACtC,SAAS,EACT,SAAS,EACT,MAAM,CACE,CAAC;AAEX,MAAM,MAAM,uBAAuB,GACjC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,SAAS,GAAG,kBAAkB,GAAG,OAAO,CAAC;AAEhF,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEjE,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAExE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,qBAAqB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,uBAAuB,CAAC;CACjC;AAED,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,gBAAgB,CAAC;IACvB,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,uBAAuB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"instructions.types.d.ts","sourceRoot":"","sources":["../../../src/commands/instructions/instructions.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,64 @@
|
|
|
1
|
-
import type { InstructionSyncStrategy, InstructionActionRecord, InstructionEntry, InstructionsJsonPayload, InstructionsMode, InstructionsScanOptions, InstructionsScanDependencies, InstructionsSummary } from './instructions.types.js';
|
|
1
|
+
import type { InstructionSyncStrategy, InstructionActionRecord, InstructionEntry, InstructionsJsonPayload, InstructionsMode, InstructionPointerExclusions, InstructionsScanOptions, InstructionsScanDependencies, InstructionsSummary } from './instructions.types.js';
|
|
2
2
|
export declare const EXPECTED_CLAUDE_CONTENT = "@AGENTS.md\n";
|
|
3
3
|
export declare const DEFAULT_INSTRUCTION_SYNC_STRATEGY: InstructionSyncStrategy;
|
|
4
4
|
interface BuildInstructionsPayloadArgs {
|
|
5
5
|
mode: InstructionsMode;
|
|
6
6
|
entries: InstructionEntry[];
|
|
7
7
|
actions: InstructionActionRecord[];
|
|
8
|
+
excludedPaths?: string[];
|
|
9
|
+
effectiveExcludedPaths?: string[];
|
|
10
|
+
exclusionWarnings?: string[];
|
|
8
11
|
}
|
|
9
12
|
export declare function resolveInstructionSyncStrategy(strategy?: InstructionSyncStrategy): InstructionSyncStrategy;
|
|
13
|
+
/**
|
|
14
|
+
* Canonicalize repo-relative exclusion entries into the exact form the scan
|
|
15
|
+
* compares against: POSIX separators, collapsed `.` and `..` segments and
|
|
16
|
+
* duplicate slashes, no trailing slash, de-duplicated, order-preserving.
|
|
17
|
+
*
|
|
18
|
+
* Full normalization is what makes the comparison trustworthy. The scan tests
|
|
19
|
+
* an exclusion against `relative(repoRoot, entryPath)`, which is always
|
|
20
|
+
* already-normalized, so an un-normalized entry like `apps/./docs` or
|
|
21
|
+
* `apps//docs` would silently never match and quietly fail open.
|
|
22
|
+
*
|
|
23
|
+
* Two classes of entry are dropped rather than normalized:
|
|
24
|
+
*
|
|
25
|
+
* - anything resolving to the repository root (`.`, `` , `./`), because
|
|
26
|
+
* excluding the root would silence the entire scan — including the
|
|
27
|
+
* `.oat/repo` carve-in — from one stray config value; and
|
|
28
|
+
* - absolute paths and entries escaping the repository (`..`, `../x`), which
|
|
29
|
+
* can never name a directory inside the tree being scanned. Dropping them
|
|
30
|
+
* keeps a malformed value from masquerading as a matchable exclusion.
|
|
31
|
+
*/
|
|
32
|
+
export declare function normalizeExcludedPaths(excludedPaths?: readonly string[]): string[];
|
|
33
|
+
/**
|
|
34
|
+
* The directories `oat instructions sync` and `oat instructions validate` skip:
|
|
35
|
+
* the derived documentation content root first, then the explicit
|
|
36
|
+
* `documentation.instructionPointerExcludes` opt-outs.
|
|
37
|
+
*
|
|
38
|
+
* Both commands resolve exclusions through this one function. That is the
|
|
39
|
+
* property that matters: if they computed exclusions separately, validate
|
|
40
|
+
* could report drift in a directory sync refuses to touch, and the repository
|
|
41
|
+
* would have no clean state to reach.
|
|
42
|
+
*
|
|
43
|
+
* Every configured entry is classified rather than trusted. An entry that is
|
|
44
|
+
* dropped during normalization, names an unexcludable carve-in root, or does
|
|
45
|
+
* not resolve to a real case-exact directory is reported as a warning and kept
|
|
46
|
+
* out of `effective`, so no caller can mistake a typo for protection.
|
|
47
|
+
*
|
|
48
|
+
* `effective` answers "is this tree protected from pointer writes?", not "did
|
|
49
|
+
* the exclusion predicate fire for it". An entry that names an already-skipped
|
|
50
|
+
* built-in root (`.git`, `node_modules`) or sits beneath another exclusion is
|
|
51
|
+
* still effective, because the operator's intent holds; warning about those
|
|
52
|
+
* would be a false alarm about exclusions that do work.
|
|
53
|
+
*
|
|
54
|
+
* Nothing here deletes or rewrites an existing pointer. Excluding a directory
|
|
55
|
+
* only stops it being reported and written; a `CLAUDE.md` already inside an
|
|
56
|
+
* excluded tree is left exactly as it is.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveInstructionPointerExcludes(repoRoot: string, overrides?: Partial<InstructionsScanDependencies>): Promise<InstructionPointerExclusions>;
|
|
10
59
|
export declare function scanInstructionFiles(repoRoot: string, options?: InstructionsScanOptions, overrides?: Partial<InstructionsScanDependencies>): Promise<InstructionEntry[]>;
|
|
11
60
|
export declare function buildInstructionsSummary(entries: InstructionEntry[], actions: InstructionActionRecord[]): InstructionsSummary;
|
|
12
|
-
export declare function buildInstructionsPayload({ mode, entries, actions, }: BuildInstructionsPayloadArgs): InstructionsJsonPayload;
|
|
61
|
+
export declare function buildInstructionsPayload({ mode, entries, actions, excludedPaths, effectiveExcludedPaths, exclusionWarnings, }: BuildInstructionsPayloadArgs): InstructionsJsonPayload;
|
|
13
62
|
export declare function formatInstructionsReport(payload: InstructionsJsonPayload, repoRoot?: string): string;
|
|
14
63
|
export {};
|
|
15
64
|
//# sourceMappingURL=instructions.utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.utils.d.ts","sourceRoot":"","sources":["../../../src/commands/instructions/instructions.utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"instructions.utils.d.ts","sourceRoot":"","sources":["../../../src/commands/instructions/instructions.utils.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACvB,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,4BAA4B,EAC5B,uBAAuB,EACvB,4BAA4B,EAE5B,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,uBAAuB,iBAAiB,CAAC;AACtD,eAAO,MAAM,iCAAiC,EAAE,uBACrC,CAAC;AAcZ,UAAU,4BAA4B;IACpC,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnC,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAiCD,wBAAgB,8BAA8B,CAC5C,QAAQ,CAAC,EAAE,uBAAuB,GACjC,uBAAuB,CAEzB;AA2ED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,GAAE,SAAS,MAAM,EAAO,GACpC,MAAM,EAAE,CAyBV;AAsDD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,iCAAiC,CACrD,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM,GACpD,OAAO,CAAC,4BAA4B,CAAC,CAuEvC;AAgID,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B,EACrC,SAAS,GAAE,OAAO,CAAC,4BAA4B,CAAM,GACpD,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAkO7B;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,OAAO,EAAE,uBAAuB,EAAE,GACjC,mBAAmB,CAoBrB;AAgBD,wBAAgB,wBAAwB,CAAC,EACvC,IAAI,EACJ,OAAO,EACP,OAAO,EACP,aAAa,EACb,sBAAsB,EACtB,iBAAiB,GAClB,EAAE,4BAA4B,GAAG,uBAAuB,CAgCxD;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,uBAAuB,EAChC,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,CAmCR"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { lstat, readdir, readFile, readlink, realpath, stat, } from 'node:fs/promises';
|
|
2
|
-
import { dirname, join, relative, resolve } from 'node:path';
|
|
2
|
+
import { dirname, join, posix, relative, resolve } from 'node:path';
|
|
3
|
+
import { readOatConfig, resolveDocumentationContentRoot, } from '../../config/oat-config.js';
|
|
3
4
|
export const EXPECTED_CLAUDE_CONTENT = '@AGENTS.md\n';
|
|
4
5
|
export const DEFAULT_INSTRUCTION_SYNC_STRATEGY = 'pointer';
|
|
5
6
|
const ROOT_EXCLUDED_DIRECTORIES = new Set(['.git', '.oat', '.worktrees']);
|
|
@@ -87,7 +88,171 @@ function recordInstructionFile(directoryEntries, directoryPath, entryName, entry
|
|
|
87
88
|
}
|
|
88
89
|
directoryEntries.set(directoryPath, current);
|
|
89
90
|
}
|
|
90
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Canonicalize repo-relative exclusion entries into the exact form the scan
|
|
93
|
+
* compares against: POSIX separators, collapsed `.` and `..` segments and
|
|
94
|
+
* duplicate slashes, no trailing slash, de-duplicated, order-preserving.
|
|
95
|
+
*
|
|
96
|
+
* Full normalization is what makes the comparison trustworthy. The scan tests
|
|
97
|
+
* an exclusion against `relative(repoRoot, entryPath)`, which is always
|
|
98
|
+
* already-normalized, so an un-normalized entry like `apps/./docs` or
|
|
99
|
+
* `apps//docs` would silently never match and quietly fail open.
|
|
100
|
+
*
|
|
101
|
+
* Two classes of entry are dropped rather than normalized:
|
|
102
|
+
*
|
|
103
|
+
* - anything resolving to the repository root (`.`, `` , `./`), because
|
|
104
|
+
* excluding the root would silence the entire scan — including the
|
|
105
|
+
* `.oat/repo` carve-in — from one stray config value; and
|
|
106
|
+
* - absolute paths and entries escaping the repository (`..`, `../x`), which
|
|
107
|
+
* can never name a directory inside the tree being scanned. Dropping them
|
|
108
|
+
* keeps a malformed value from masquerading as a matchable exclusion.
|
|
109
|
+
*/
|
|
110
|
+
export function normalizeExcludedPaths(excludedPaths = []) {
|
|
111
|
+
const normalized = [];
|
|
112
|
+
for (const candidate of excludedPaths) {
|
|
113
|
+
const trimmed = toPosixPath(candidate.trim());
|
|
114
|
+
if (!trimmed || posix.isAbsolute(trimmed)) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const posixPath = posix.normalize(trimmed).replace(/\/+$/, '');
|
|
118
|
+
if (!posixPath ||
|
|
119
|
+
posixPath === '.' ||
|
|
120
|
+
posixPath === '..' ||
|
|
121
|
+
posixPath.startsWith('../')) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!normalized.includes(posixPath)) {
|
|
125
|
+
normalized.push(posixPath);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return normalized;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Paths the carve-in queues directly, which therefore never reach the exclusion
|
|
132
|
+
* predicate and can never be excluded however the config asks. An opt-out
|
|
133
|
+
* naming one of these is inert and must be reported as such rather than
|
|
134
|
+
* silently listed as protection.
|
|
135
|
+
*
|
|
136
|
+
* Matched exactly, never by prefix: only the carve-in root itself bypasses the
|
|
137
|
+
* predicate. Its *descendants* are reached by ordinary traversal out of the
|
|
138
|
+
* queued directory, so `.oat/repo/pjm` is excludable even though `.oat/repo`
|
|
139
|
+
* is not, and treating it as inert would be a false warning about an exclusion
|
|
140
|
+
* that really does protect its tree.
|
|
141
|
+
*/
|
|
142
|
+
const UNEXCLUDABLE_PATHS = new Set([...ROOT_EXCLUDED_DIRECTORY_CARVE_INS].map(([directory, carveIn]) => `${directory}/${carveIn}`));
|
|
143
|
+
/**
|
|
144
|
+
* Whether `relativePath` names a real directory whose on-disk spelling matches
|
|
145
|
+
* exactly.
|
|
146
|
+
*
|
|
147
|
+
* The case check is the point. On a case-insensitive filesystem (APFS, NTFS) a
|
|
148
|
+
* plain existence test accepts `Apps/Docsapp/docs` for a directory really named
|
|
149
|
+
* `apps/docsapp/docs`, but the scan compares against `relative(repoRoot, ...)`,
|
|
150
|
+
* which always yields the true on-disk case. The exclusion would then be
|
|
151
|
+
* reported as applied while matching nothing — issue #238 recurring silently on
|
|
152
|
+
* the default developer platform. Resolving through `realpath` and comparing
|
|
153
|
+
* the result to the requested spelling catches that, and returns false for a
|
|
154
|
+
* path that does not exist at all.
|
|
155
|
+
*
|
|
156
|
+
* `repoRoot` is realpath'd too, so a symlinked checkout (`/tmp` on macOS) does
|
|
157
|
+
* not make every entry look like a mismatch.
|
|
158
|
+
*/
|
|
159
|
+
async function isCaseExactDirectory(dependencies, repoRoot, relativePath) {
|
|
160
|
+
try {
|
|
161
|
+
const realRoot = await dependencies.realpath(repoRoot);
|
|
162
|
+
const candidate = join(realRoot, relativePath);
|
|
163
|
+
if (!(await directoryExists(dependencies, candidate))) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const realCandidate = await dependencies.realpath(candidate);
|
|
167
|
+
return toPosixPath(relative(realRoot, realCandidate)) === relativePath;
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The directories `oat instructions sync` and `oat instructions validate` skip:
|
|
175
|
+
* the derived documentation content root first, then the explicit
|
|
176
|
+
* `documentation.instructionPointerExcludes` opt-outs.
|
|
177
|
+
*
|
|
178
|
+
* Both commands resolve exclusions through this one function. That is the
|
|
179
|
+
* property that matters: if they computed exclusions separately, validate
|
|
180
|
+
* could report drift in a directory sync refuses to touch, and the repository
|
|
181
|
+
* would have no clean state to reach.
|
|
182
|
+
*
|
|
183
|
+
* Every configured entry is classified rather than trusted. An entry that is
|
|
184
|
+
* dropped during normalization, names an unexcludable carve-in root, or does
|
|
185
|
+
* not resolve to a real case-exact directory is reported as a warning and kept
|
|
186
|
+
* out of `effective`, so no caller can mistake a typo for protection.
|
|
187
|
+
*
|
|
188
|
+
* `effective` answers "is this tree protected from pointer writes?", not "did
|
|
189
|
+
* the exclusion predicate fire for it". An entry that names an already-skipped
|
|
190
|
+
* built-in root (`.git`, `node_modules`) or sits beneath another exclusion is
|
|
191
|
+
* still effective, because the operator's intent holds; warning about those
|
|
192
|
+
* would be a false alarm about exclusions that do work.
|
|
193
|
+
*
|
|
194
|
+
* Nothing here deletes or rewrites an existing pointer. Excluding a directory
|
|
195
|
+
* only stops it being reported and written; a `CLAUDE.md` already inside an
|
|
196
|
+
* excluded tree is left exactly as it is.
|
|
197
|
+
*/
|
|
198
|
+
export async function resolveInstructionPointerExcludes(repoRoot, overrides = {}) {
|
|
199
|
+
const dependencies = {
|
|
200
|
+
lstat,
|
|
201
|
+
realpath,
|
|
202
|
+
readdir,
|
|
203
|
+
readFile,
|
|
204
|
+
readlink,
|
|
205
|
+
stat,
|
|
206
|
+
...overrides,
|
|
207
|
+
};
|
|
208
|
+
const config = await readOatConfig(repoRoot);
|
|
209
|
+
const contentRoot = await resolveDocumentationContentRoot(repoRoot, config, {
|
|
210
|
+
// Probe through the injected `stat` so a simulated filesystem (tests) and
|
|
211
|
+
// the real one agree on whether `<root>/docs` exists.
|
|
212
|
+
dirExists: async (path) => {
|
|
213
|
+
try {
|
|
214
|
+
return (await dependencies.stat(path)).isDirectory();
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
const requested = [
|
|
222
|
+
...(contentRoot === null
|
|
223
|
+
? []
|
|
224
|
+
: [{ raw: contentRoot, source: 'documentation.root' }]),
|
|
225
|
+
...(config.documentation?.instructionPointerExcludes ?? []).map((raw) => ({
|
|
226
|
+
raw,
|
|
227
|
+
source: 'documentation.instructionPointerExcludes',
|
|
228
|
+
})),
|
|
229
|
+
];
|
|
230
|
+
const configured = [];
|
|
231
|
+
const effective = [];
|
|
232
|
+
const warnings = [];
|
|
233
|
+
for (const { raw, source } of requested) {
|
|
234
|
+
const [normalizedPath] = normalizeExcludedPaths([raw]);
|
|
235
|
+
if (!normalizedPath) {
|
|
236
|
+
warnings.push(`Ignoring ${source} entry ${JSON.stringify(raw)}: exclusions must be repository-relative paths inside the repository.`);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (configured.includes(normalizedPath)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
configured.push(normalizedPath);
|
|
243
|
+
if (UNEXCLUDABLE_PATHS.has(normalizedPath)) {
|
|
244
|
+
warnings.push(`${source} entry ${JSON.stringify(normalizedPath)} has no effect: ${normalizedPath} is always scanned.`);
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (!(await isCaseExactDirectory(dependencies, repoRoot, normalizedPath))) {
|
|
248
|
+
warnings.push(`${source} entry ${JSON.stringify(normalizedPath)} matches no directory in this repository (matching is case-sensitive), so it excludes nothing.`);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
effective.push(normalizedPath);
|
|
252
|
+
}
|
|
253
|
+
return { configured, effective, warnings };
|
|
254
|
+
}
|
|
255
|
+
async function scanInstructionDirectories(repoRoot, dependencies, debug, excludedPaths = new Set()) {
|
|
91
256
|
const queue = [repoRoot];
|
|
92
257
|
const directoryEntries = new Map();
|
|
93
258
|
while (queue.length > 0) {
|
|
@@ -123,6 +288,19 @@ async function scanInstructionDirectories(repoRoot, dependencies, debug) {
|
|
|
123
288
|
}
|
|
124
289
|
continue;
|
|
125
290
|
}
|
|
291
|
+
// Deliberately after the carve-in above, never before it: the carve-in
|
|
292
|
+
// path is already queued by the time a configured exclusion is tested,
|
|
293
|
+
// so excluding `.oat` (or any documentation root that happens to
|
|
294
|
+
// contain one) still leaves `.oat/repo/**` scanned. Skipping the
|
|
295
|
+
// directory here also skips its whole subtree, because a directory
|
|
296
|
+
// that is never queued is never read.
|
|
297
|
+
if (excludedPaths.size > 0) {
|
|
298
|
+
const relativePath = toPosixPath(relative(repoRoot, entryPath));
|
|
299
|
+
if (excludedPaths.has(relativePath)) {
|
|
300
|
+
debug?.(`Skipping excluded directory ${relativePath}`);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
126
304
|
queue.push(entryPath);
|
|
127
305
|
continue;
|
|
128
306
|
}
|
|
@@ -181,7 +359,7 @@ export async function scanInstructionFiles(repoRoot, options = {}, overrides = {
|
|
|
181
359
|
stat,
|
|
182
360
|
...overrides,
|
|
183
361
|
};
|
|
184
|
-
const instructionDirectories = await scanInstructionDirectories(repoRoot, dependencies, options.debug);
|
|
362
|
+
const instructionDirectories = await scanInstructionDirectories(repoRoot, dependencies, options.debug, new Set(normalizeExcludedPaths(options.excludedPaths)));
|
|
185
363
|
const entries = [];
|
|
186
364
|
for (const [directoryPath, directoryEntry] of instructionDirectories) {
|
|
187
365
|
const agentsPath = directoryEntry.agentsPath ?? null;
|
|
@@ -402,15 +580,34 @@ function deriveInstructionsStatus(entries, actions) {
|
|
|
402
580
|
}
|
|
403
581
|
return 'ok';
|
|
404
582
|
}
|
|
405
|
-
export function buildInstructionsPayload({ mode, entries, actions, }) {
|
|
583
|
+
export function buildInstructionsPayload({ mode, entries, actions, excludedPaths, effectiveExcludedPaths, exclusionWarnings, }) {
|
|
406
584
|
const normalizedEntries = normalizeEntries(entries);
|
|
407
585
|
const normalizedActions = normalizeActions(actions);
|
|
586
|
+
const normalizedExcludedPaths = normalizeExcludedPaths(excludedPaths);
|
|
587
|
+
const normalizedEffectivePaths = normalizeExcludedPaths(effectiveExcludedPaths);
|
|
408
588
|
return {
|
|
409
589
|
mode,
|
|
410
590
|
status: deriveInstructionsStatus(normalizedEntries, normalizedActions),
|
|
411
591
|
summary: buildInstructionsSummary(normalizedEntries, normalizedActions),
|
|
412
592
|
entries: normalizedEntries,
|
|
413
593
|
actions: normalizedActions,
|
|
594
|
+
// Both omitted when nothing is configured, so a repository with no
|
|
595
|
+
// documentation root keeps its existing payload shape exactly. Once
|
|
596
|
+
// `excludedPaths` is present its effective counterpart always is too, even
|
|
597
|
+
// when empty: "configured three, protected none" is precisely the state a
|
|
598
|
+
// consumer must be able to see, and omitting the field would hide it.
|
|
599
|
+
...(normalizedExcludedPaths.length > 0
|
|
600
|
+
? {
|
|
601
|
+
excludedPaths: normalizedExcludedPaths,
|
|
602
|
+
effectiveExcludedPaths: normalizedEffectivePaths,
|
|
603
|
+
}
|
|
604
|
+
: {}),
|
|
605
|
+
// Independent of the two fields above: an entry rejected during
|
|
606
|
+
// normalization produces a warning but no configured path, and that is
|
|
607
|
+
// exactly the case a JSON consumer must still be able to see.
|
|
608
|
+
...(exclusionWarnings !== undefined && exclusionWarnings.length > 0
|
|
609
|
+
? { exclusionWarnings }
|
|
610
|
+
: {}),
|
|
414
611
|
};
|
|
415
612
|
}
|
|
416
613
|
export function formatInstructionsReport(payload, repoRoot) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/commands/instructions/sync/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,EAAE,EAAsB,MAAM,kBAAkB,CAAC;AAI3E,OAAO,EAKL,KAAK,mCAAmC,EACzC,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/commands/instructions/sync/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,EAAE,EAAsB,MAAM,kBAAkB,CAAC;AAI3E,OAAO,EAKL,KAAK,mCAAmC,EACzC,MAAM,2CAA2C,CAAC;AAanD,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAQ5C,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,OAAO,EAAO,GACrB,OAAO,CAAC,IAAI,CAAC,CAEf;AAgTD,wBAAgB,6BAA6B,CAC3C,SAAS,GAAE,OAAO,CAAC,mCAAmC,CAAM,GAC3D,OAAO,CAwGT"}
|
|
@@ -2,7 +2,7 @@ import { lstat, readFile, rm, symlink, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import { dirname, join, relative } from 'node:path';
|
|
3
3
|
import { buildCommandContext } from '../../../app/command-context.js';
|
|
4
4
|
import { INSTRUCTION_SYNC_STRATEGIES, } from '../../instructions/instructions.types.js';
|
|
5
|
-
import { buildInstructionsPayload, DEFAULT_INSTRUCTION_SYNC_STRATEGY, EXPECTED_CLAUDE_CONTENT, formatInstructionsReport, resolveInstructionSyncStrategy, scanInstructionFiles, } from '../../instructions/instructions.utils.js';
|
|
5
|
+
import { buildInstructionsPayload, DEFAULT_INSTRUCTION_SYNC_STRATEGY, EXPECTED_CLAUDE_CONTENT, formatInstructionsReport, resolveInstructionPointerExcludes, resolveInstructionSyncStrategy, scanInstructionFiles, } from '../../instructions/instructions.utils.js';
|
|
6
6
|
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
7
7
|
import { CliError } from '../../../errors/cli-error.js';
|
|
8
8
|
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
@@ -16,6 +16,7 @@ function defaultDependencies() {
|
|
|
16
16
|
lstat,
|
|
17
17
|
readFile,
|
|
18
18
|
removeFile: removeInstructionFile,
|
|
19
|
+
resolveInstructionPointerExcludes,
|
|
19
20
|
resolveProjectRoot,
|
|
20
21
|
scanInstructionFiles,
|
|
21
22
|
symlinkFile: async (target, path) => {
|
|
@@ -249,7 +250,14 @@ export function createInstructionsSyncCommand(overrides = {}) {
|
|
|
249
250
|
try {
|
|
250
251
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
251
252
|
const strategy = resolveInstructionSyncStrategy(options.strategy);
|
|
253
|
+
const exclusions = await dependencies.resolveInstructionPointerExcludes(repoRoot);
|
|
254
|
+
// Warned before any work: an operator whose opt-out silently matches
|
|
255
|
+
// nothing must hear about it even when the sync then succeeds.
|
|
256
|
+
for (const warning of exclusions.warnings) {
|
|
257
|
+
context.logger.warn(warning);
|
|
258
|
+
}
|
|
252
259
|
const entries = await dependencies.scanInstructionFiles(repoRoot, {
|
|
260
|
+
excludedPaths: exclusions.configured,
|
|
253
261
|
strategy,
|
|
254
262
|
});
|
|
255
263
|
const plannedActions = planSyncActions({
|
|
@@ -267,6 +275,9 @@ export function createInstructionsSyncCommand(overrides = {}) {
|
|
|
267
275
|
? entries
|
|
268
276
|
: getPostSyncEntries(entries, actions, strategy),
|
|
269
277
|
actions,
|
|
278
|
+
excludedPaths: exclusions.configured,
|
|
279
|
+
effectiveExcludedPaths: exclusions.effective,
|
|
280
|
+
exclusionWarnings: exclusions.warnings,
|
|
270
281
|
});
|
|
271
282
|
if (context.json) {
|
|
272
283
|
context.logger.json(payload);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/commands/instructions/validate/validate.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uCAAuC,EAC7C,MAAM,2CAA2C,CAAC;
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/commands/instructions/validate/validate.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uCAAuC,EAC7C,MAAM,2CAA2C,CAAC;AAYnD,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAW5C,wBAAgB,iCAAiC,CAC/C,SAAS,GAAE,OAAO,CAAC,uCAAuC,CAAM,GAC/D,OAAO,CAsET"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { buildCommandContext } from '../../../app/command-context.js';
|
|
2
2
|
import { INSTRUCTION_SYNC_STRATEGIES, } from '../../instructions/instructions.types.js';
|
|
3
|
-
import { buildInstructionsPayload, DEFAULT_INSTRUCTION_SYNC_STRATEGY, formatInstructionsReport, resolveInstructionSyncStrategy, scanInstructionFiles, } from '../../instructions/instructions.utils.js';
|
|
3
|
+
import { buildInstructionsPayload, DEFAULT_INSTRUCTION_SYNC_STRATEGY, formatInstructionsReport, resolveInstructionPointerExcludes, resolveInstructionSyncStrategy, scanInstructionFiles, } from '../../instructions/instructions.utils.js';
|
|
4
4
|
import { readGlobalOptions } from '../../shared/shared.utils.js';
|
|
5
5
|
import { CliError } from '../../../errors/cli-error.js';
|
|
6
6
|
import { resolveProjectRoot } from '../../../fs/paths.js';
|
|
@@ -8,6 +8,7 @@ import { Command, Option } from 'commander';
|
|
|
8
8
|
function defaultDependencies() {
|
|
9
9
|
return {
|
|
10
10
|
buildCommandContext,
|
|
11
|
+
resolveInstructionPointerExcludes,
|
|
11
12
|
resolveProjectRoot,
|
|
12
13
|
scanInstructionFiles,
|
|
13
14
|
};
|
|
@@ -27,13 +28,23 @@ export function createInstructionsValidateCommand(overrides = {}) {
|
|
|
27
28
|
const strategy = resolveInstructionSyncStrategy(options.strategy);
|
|
28
29
|
try {
|
|
29
30
|
const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
|
|
31
|
+
const exclusions = await dependencies.resolveInstructionPointerExcludes(repoRoot);
|
|
32
|
+
// Warned before any work: an operator whose opt-out silently matches
|
|
33
|
+
// nothing must hear about it even when validate then reports `ok`.
|
|
34
|
+
for (const warning of exclusions.warnings) {
|
|
35
|
+
context.logger.warn(warning);
|
|
36
|
+
}
|
|
30
37
|
const entries = await dependencies.scanInstructionFiles(repoRoot, {
|
|
38
|
+
excludedPaths: exclusions.configured,
|
|
31
39
|
strategy,
|
|
32
40
|
});
|
|
33
41
|
const payload = buildInstructionsPayload({
|
|
34
42
|
mode: 'validate',
|
|
35
43
|
entries,
|
|
36
44
|
actions: [],
|
|
45
|
+
excludedPaths: exclusions.configured,
|
|
46
|
+
effectiveExcludedPaths: exclusions.effective,
|
|
47
|
+
exclusionWarnings: exclusions.warnings,
|
|
37
48
|
});
|
|
38
49
|
if (context.json) {
|
|
39
50
|
context.logger.json(payload);
|