@open-agent-toolkit/cli 0.2.62 → 0.2.63
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/workflow-gates.md +124 -16
- package/assets/docs/provider-sync/commands.md +3 -0
- package/assets/docs/provider-sync/instruction-sync.md +107 -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/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 +121 -121
- package/assets/skills/oat-project-complete/SKILL.md +134 -4
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +121 -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 +121 -121
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +121 -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/references/docs/autonomy-contract.md +121 -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 +121 -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/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/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/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/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/package.json +2 -2
|
@@ -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);
|
|
@@ -2,6 +2,176 @@ import { type CommandContext, type GlobalOptions } from '../../../app/command-co
|
|
|
2
2
|
import { type ActiveProjectResolution } from '../../../config/oat-config.js';
|
|
3
3
|
import { type ResolvedConfig } from '../../../config/resolve.js';
|
|
4
4
|
import { Command } from 'commander';
|
|
5
|
+
export declare const PROJECT_LOG_FILENAME = "project-log.md";
|
|
6
|
+
/**
|
|
7
|
+
* Directory, relative to a project, that holds gate partial-finalization
|
|
8
|
+
* receipts. Ignored by the repository so a receipt never dirties the tree.
|
|
9
|
+
*/
|
|
10
|
+
export declare const GATE_RECEIPTS_DIRNAME = "gate-receipts";
|
|
11
|
+
/**
|
|
12
|
+
* Bounded attempt budget for committing the project log across a transient
|
|
13
|
+
* `.git/index.lock`. Three attempts means exactly two waits, so the delays
|
|
14
|
+
* below are the whole window the persistent-versus-transient mtime comparison
|
|
15
|
+
* spans. Declared here rather than inline so the bound is reviewable and the
|
|
16
|
+
* gate and the recovery entry point share one budget.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PROJECT_LOG_COMMIT_ATTEMPTS = 3;
|
|
19
|
+
export declare const PROJECT_LOG_COMMIT_RETRY_DELAYS_MS: readonly number[];
|
|
20
|
+
/**
|
|
21
|
+
* Bounded wait for the advisory lock. Declared rather than inline so the bound
|
|
22
|
+
* is reviewable: a writer waits at most `WAIT_MS`, polling every `POLL_MS`, and
|
|
23
|
+
* treats a lock whose owner is gone — or that is older than `STALE_MS` — as
|
|
24
|
+
* abandoned.
|
|
25
|
+
*/
|
|
26
|
+
export declare const PROJECT_LOG_LOCK_WAIT_MS = 5000;
|
|
27
|
+
export declare const PROJECT_LOG_LOCK_POLL_MS = 25;
|
|
28
|
+
export declare const PROJECT_LOG_LOCK_STALE_MS = 30000;
|
|
29
|
+
export interface ProjectLogLockDependencies {
|
|
30
|
+
waitMs: number;
|
|
31
|
+
pollMs: number;
|
|
32
|
+
staleMs: number;
|
|
33
|
+
sleep: (ms: number) => Promise<void>;
|
|
34
|
+
now: () => number;
|
|
35
|
+
}
|
|
36
|
+
export declare function projectLogLockPath(logPath: string): string;
|
|
37
|
+
export type GitLockFailureClass = 'transient-index-lock' | 'persistent-index-lock' | 'other';
|
|
38
|
+
export type ProjectLogCommitOutcome = 'committed' | 'already-committed' | 'nothing-to-commit' | 'not-a-repo' | 'blocked-by-index-lock' | 'entry-missing-after-commit' | 'commit-unverified' | 'failed';
|
|
39
|
+
export interface ProjectLogCommitResult {
|
|
40
|
+
outcome: ProjectLogCommitOutcome;
|
|
41
|
+
committed: boolean;
|
|
42
|
+
attempts: number;
|
|
43
|
+
error?: string;
|
|
44
|
+
lockClass?: GitLockFailureClass;
|
|
45
|
+
}
|
|
46
|
+
export interface CommitProjectLogInput {
|
|
47
|
+
repoRoot: string;
|
|
48
|
+
logPath: string;
|
|
49
|
+
message?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Identity of the entry this commit is finalizing: the idempotency key plus
|
|
52
|
+
* the body it was written in, which together name the exact token to look
|
|
53
|
+
* for. Supplied so a settled outcome is proven rather than inferred — a clean
|
|
54
|
+
* log whose content still carries this entry is a log whose HEAD content
|
|
55
|
+
* carries it too.
|
|
56
|
+
*/
|
|
57
|
+
identity?: {
|
|
58
|
+
key: string;
|
|
59
|
+
body: string;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export interface CommitProjectLogDependencies {
|
|
63
|
+
attempts: number;
|
|
64
|
+
retryDelaysMs: readonly number[];
|
|
65
|
+
sleep: (ms: number) => Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Advisory-lock overrides. Kept separate from `sleep` above, which is the
|
|
68
|
+
* index-lock retry delay: the two waits are different bounds and a caller
|
|
69
|
+
* that observes one must not be told about the other.
|
|
70
|
+
*/
|
|
71
|
+
lock: Partial<ProjectLogLockDependencies>;
|
|
72
|
+
/**
|
|
73
|
+
* Git runner for this path. Injectable so a control can make one command
|
|
74
|
+
* fail — the committed-log read back is allowed to be unavailable, and what
|
|
75
|
+
* happens then has to be provable rather than asserted.
|
|
76
|
+
*/
|
|
77
|
+
runGit: (repoRoot: string, args: string[]) => string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Classifies a failed git invocation as an index-lock contention or a real
|
|
81
|
+
* failure.
|
|
82
|
+
*
|
|
83
|
+
* Only a stderr that actually names `index.lock` is lock contention; every
|
|
84
|
+
* other failure (hook, signing, identity, pathspec) stays `other` so it is
|
|
85
|
+
* reported rather than retried and swallowed. A lock is `persistent` only when
|
|
86
|
+
* its mtime is unchanged across the whole retry window, which is why the
|
|
87
|
+
* caller passes the mtime it observed on the first lock failure.
|
|
88
|
+
*/
|
|
89
|
+
export declare function classifyGitLockFailure(stderr: string, lockPath: string, firstObservedMtimeMs?: number): GitLockFailureClass;
|
|
90
|
+
/**
|
|
91
|
+
* Whether the log *as committed at HEAD* carries a given entry identity.
|
|
92
|
+
*
|
|
93
|
+
* `unknown` is a first-class answer, and it is never read as `absent`: a
|
|
94
|
+
* repository with no HEAD, a log that has never been committed, or a git
|
|
95
|
+
* invocation that fails for an environmental reason all say nothing about the
|
|
96
|
+
* entry, and turning that silence into "the entry is gone" would manufacture
|
|
97
|
+
* failures out of missing evidence.
|
|
98
|
+
*/
|
|
99
|
+
export type CommittedLogIdentityState = 'present' | 'absent' | 'unknown';
|
|
100
|
+
/**
|
|
101
|
+
* Whether the committed log carries `key`.
|
|
102
|
+
*
|
|
103
|
+
* Exported for callers that must distinguish finished finalization from
|
|
104
|
+
* unfinished finalization — the gate's receipt classifier among them — so that
|
|
105
|
+
* question is answered by this module rather than by a caller opening
|
|
106
|
+
* `project-log.md` itself (DR-260718).
|
|
107
|
+
*/
|
|
108
|
+
export declare function committedProjectLogIdentityState(repoRoot: string, logPath: string, key: string, body?: string): Promise<CommittedLogIdentityState>;
|
|
109
|
+
/**
|
|
110
|
+
* Stages and commits `project-log.md`, retrying a bounded number of times when
|
|
111
|
+
* the failure is a transient `.git/index.lock`.
|
|
112
|
+
*
|
|
113
|
+
* The log is tracked, so an uncommitted append leaves the worktree dirty for
|
|
114
|
+
* whatever runs next — including a dispatched subagent whose preflight requires
|
|
115
|
+
* a clean tree. The commit is pathspec-scoped to the log alone so unrelated
|
|
116
|
+
* working-tree changes are never swept in.
|
|
117
|
+
*
|
|
118
|
+
* Scope note: this commits the whole log file, so a log that was already dirty
|
|
119
|
+
* before the caller ran is committed along with this entry. That is deliberate
|
|
120
|
+
* — leaving the earlier append uncommitted would reproduce the dirty tree this
|
|
121
|
+
* exists to prevent — but it does mean the commit is not always exactly one
|
|
122
|
+
* entry.
|
|
123
|
+
*
|
|
124
|
+
* Never throws, and never deletes, moves, or forces an index lock: a lock this
|
|
125
|
+
* process did not take is another process's, and only its owner may clear it.
|
|
126
|
+
* Git failures are reported to the caller, which degrades to a diagnostic
|
|
127
|
+
* rather than altering any exit status. On failure the index is restored so a
|
|
128
|
+
* partially staged log is not left behind.
|
|
129
|
+
*
|
|
130
|
+
* Exactly one outcome is derived from a single pre-action snapshot (entry HEAD
|
|
131
|
+
* plus entry dirtiness) rather than from eligibility re-sampled after the
|
|
132
|
+
* action, so a log another writer committed mid-retry reads as
|
|
133
|
+
* `already-committed` instead of a spurious failure.
|
|
134
|
+
*/
|
|
135
|
+
export declare function commitProjectLog(input: CommitProjectLogInput, overrides?: Partial<CommitProjectLogDependencies>): Promise<ProjectLogCommitResult>;
|
|
136
|
+
/**
|
|
137
|
+
* Returns the heading of the first existing entry whose body already carries
|
|
138
|
+
* this idempotency identity, or undefined when the log has no such entry.
|
|
139
|
+
*
|
|
140
|
+
* With `body` supplied the match is the exact whole-word token derived from it;
|
|
141
|
+
* without one — the advisory staleness check, which has only a run id — any
|
|
142
|
+
* word containing `key` counts. Callers that must not duplicate an entry always
|
|
143
|
+
* pass the body.
|
|
144
|
+
*
|
|
145
|
+
* The scan lives here, in the log module, because log reads and mutations are
|
|
146
|
+
* CLI-owned (DR-260718); callers such as the gate never open `project-log.md`
|
|
147
|
+
* themselves.
|
|
148
|
+
*/
|
|
149
|
+
export declare function findProjectLogEntryByIdempotencyKey(content: string, key: string, body?: string): string | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* Durable record of a gate project-log append that was written but could not be
|
|
152
|
+
* committed. It carries everything the recovery command needs to finish the
|
|
153
|
+
* finalization from a later process, and enough identity to refuse when the
|
|
154
|
+
* tree it describes is no longer the tree it is replayed against.
|
|
155
|
+
*/
|
|
156
|
+
export interface GateProjectLogReceipt {
|
|
157
|
+
runId: string;
|
|
158
|
+
project: string;
|
|
159
|
+
projectPath: string;
|
|
160
|
+
worktreeRoot: string;
|
|
161
|
+
logPath: string;
|
|
162
|
+
artifactPath: string | null;
|
|
163
|
+
artifactSignature: string | null;
|
|
164
|
+
appendStatus: 'appended' | 'already-appended';
|
|
165
|
+
commitStatus: ProjectLogCommitOutcome;
|
|
166
|
+
lockClass: GitLockFailureClass | null;
|
|
167
|
+
attempts: number;
|
|
168
|
+
producer: string;
|
|
169
|
+
ref: string;
|
|
170
|
+
body: string;
|
|
171
|
+
recovery: {
|
|
172
|
+
command: string;
|
|
173
|
+
};
|
|
174
|
+
}
|
|
5
175
|
export interface AppendProjectLogInput {
|
|
6
176
|
repoRoot: string;
|
|
7
177
|
home?: string;
|
|
@@ -14,12 +184,18 @@ export interface AppendProjectLogInput {
|
|
|
14
184
|
ref?: string;
|
|
15
185
|
body?: string;
|
|
16
186
|
versionNote?: string;
|
|
187
|
+
idempotencyKey?: string;
|
|
17
188
|
}
|
|
18
189
|
export type ProjectLogAppendResult = {
|
|
19
190
|
status: 'appended';
|
|
20
191
|
logPath: string;
|
|
21
192
|
heading: string;
|
|
22
193
|
created: boolean;
|
|
194
|
+
} | {
|
|
195
|
+
status: 'already-appended';
|
|
196
|
+
logPath: string;
|
|
197
|
+
heading: string;
|
|
198
|
+
created: false;
|
|
23
199
|
} | {
|
|
24
200
|
status: 'skipped';
|
|
25
201
|
reason: 'projectLog=false';
|
|
@@ -29,6 +205,16 @@ export interface AppendProjectLogDependencies {
|
|
|
29
205
|
resolveEffectiveConfig: (repoRoot: string, userConfigDir: string, env?: NodeJS.ProcessEnv) => Promise<ResolvedConfig>;
|
|
30
206
|
resolveAssetsRoot: () => Promise<string>;
|
|
31
207
|
now: () => Date;
|
|
208
|
+
/**
|
|
209
|
+
* The log's own read/modify/write primitives. Injectable so a test can hold
|
|
210
|
+
* one writer inside the window while another enters it, which is the only way
|
|
211
|
+
* to prove the serialization rather than assert it.
|
|
212
|
+
*/
|
|
213
|
+
readLog: (path: string) => Promise<string>;
|
|
214
|
+
writeLog: (path: string, content: string) => Promise<void>;
|
|
215
|
+
appendLog: (path: string, content: string) => Promise<void>;
|
|
216
|
+
/** Advisory-lock overrides for the append window. */
|
|
217
|
+
lock: Partial<ProjectLogLockDependencies>;
|
|
32
218
|
}
|
|
33
219
|
export interface ProjectLogAppendCommandDependencies extends AppendProjectLogDependencies {
|
|
34
220
|
buildCommandContext: (options: GlobalOptions) => CommandContext;
|
|
@@ -36,6 +222,15 @@ export interface ProjectLogAppendCommandDependencies extends AppendProjectLogDep
|
|
|
36
222
|
readStdin: () => Promise<string>;
|
|
37
223
|
}
|
|
38
224
|
export declare function instantiateProjectLogTemplate(template: string, projectName: string, date: string): string;
|
|
225
|
+
/**
|
|
226
|
+
* Appends one entry to the project log, at most once per idempotency key.
|
|
227
|
+
*
|
|
228
|
+
* The existence check, the idempotency scan, the template instantiation, and
|
|
229
|
+
* the write are one critical section under the log's advisory lock. Separating
|
|
230
|
+
* the scan from the mutation is what let two overlapping writers both pass the
|
|
231
|
+
* scan and then lose one entry to the other's stale rewrite, so they are not
|
|
232
|
+
* separable here.
|
|
233
|
+
*/
|
|
39
234
|
export declare function appendProjectLog(input: AppendProjectLogInput, overrides?: Partial<AppendProjectLogDependencies>): Promise<ProjectLogAppendResult>;
|
|
40
235
|
export declare function createProjectLogAppendCommand(overrides?: Partial<ProjectLogAppendCommandDependencies>): Command;
|
|
41
236
|
//# sourceMappingURL=append.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/log/append.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/log/append.ts"],"names":[],"mappings":"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"}
|