devflow-kit 3.8.0 → 3.9.0
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/CHANGELOG.md +120 -0
- package/README.md +5 -5
- package/dist/agents/code.md +4 -4
- package/dist/agents/fix.md +1 -1
- package/dist/agents/git.md +2 -2
- package/dist/agents/skim.md +1 -1
- package/dist/agents/triage.md +7 -0
- package/dist/cli/commands/curation.js +67 -16
- package/dist/cli/commands/gate-level-prompts.js +8 -6
- package/dist/cli/commands/gates.js +5 -4
- package/dist/cli/commands/init.js +8 -7
- package/dist/cli/commands/memory.js +59 -12
- package/dist/cli/commands/uninstall.js +77 -9
- package/dist/commands/bug-analysis.md +2 -2
- package/dist/commands/code-review.md +11 -11
- package/dist/commands/debug.md +2 -2
- package/dist/commands/dynamic-build.md +2 -2
- package/dist/commands/dynamic-plan.md +2 -2
- package/dist/commands/dynamic-profile.md +2 -2
- package/dist/commands/dynamic-tickets.md +2 -2
- package/dist/commands/explore.md +2 -2
- package/dist/commands/implement.md +2 -2
- package/dist/commands/plan.md +2 -2
- package/dist/commands/release.md +2 -2
- package/dist/commands/research.md +2 -2
- package/dist/commands/resolve.md +16 -16
- package/dist/commands/self-review.md +2 -2
- package/dist/core/area-pause-notice.js +44 -0
- package/dist/core/curation-move-skip.js +4 -5
- package/dist/core/curation-queue-cleanup.js +6 -5
- package/dist/core/curation-store.js +1 -0
- package/dist/core/evidence-policy.js +10 -8
- package/dist/core/plugins.js +4 -4
- package/dist/core/tracked-areas.js +138 -14
- package/dist/curation-off/agents/code.md +4 -4
- package/dist/curation-off/agents/fix.md +1 -1
- package/dist/curation-off/agents/triage.md +7 -0
- package/dist/curation-off/commands/code-review.md +11 -11
- package/dist/curation-off/commands/debug.md +2 -2
- package/dist/curation-off/commands/dynamic-build.md +2 -2
- package/dist/curation-off/commands/explore.md +2 -2
- package/dist/curation-off/commands/implement.md +2 -2
- package/dist/curation-off/commands/plan.md +2 -2
- package/dist/curation-off/commands/resolve.md +16 -16
- package/dist/curation-off/commands/self-review.md +2 -2
- package/dist/hud/components/curation-counts.js +27 -0
- package/dist/skills/git/references/pr/post-resolution-summary.md +12 -11
- package/dist/skills/git/references/pr/post-review-summary.md +12 -11
- package/dist/skills/git/references/pr/update-pr-evidence.md +2 -2
- package/dist/skills/git/references/publication-gate.md +6 -7
- package/dist/skills/git/references/tracker/github/manage-debt.md +6 -2
- package/dist/skills/git/references/tracker/jira/manage-debt.md +6 -2
- package/dist/skills/git/references/tracker/linear/manage-debt.md +6 -2
- package/package.json +1 -1
- package/src/assets/agents/code.mds +4 -4
- package/src/assets/agents/evaluate.md +6 -12
- package/src/assets/agents/fix.mds +1 -1
- package/src/assets/agents/git.mds +2 -2
- package/src/assets/agents/skim.mds +1 -1
- package/src/assets/agents/triage.mds +7 -0
- package/src/assets/agents/validate.md +20 -27
- package/src/assets/commands/_partials/_decisions.mds +10 -8
- package/src/assets/commands/_partials/_settings.mds +2 -2
- package/src/assets/commands/code-review.mds +9 -9
- package/src/assets/commands/resolve.mds +14 -14
- package/src/assets/mds/git/_ops.mds +6 -1
- package/src/assets/mds/git/_ops_pr.mds +20 -10
- package/src/assets/mds/git/_ops_steps.mds +10 -0
- package/src/assets/mds/git/_pr.mds +14 -14
- package/src/assets/mds/git/_references.mds +6 -7
- package/src/assets/mds/tracker/_github.mds +1 -4
- package/src/assets/mds/tracker/_jira.mds +1 -4
- package/src/assets/mds/tracker/_linear.mds +1 -4
- package/src/assets/scripts/ci-wait.cjs +389 -92
- package/src/assets/scripts/hooks/background-memory-update +79 -1
- package/src/assets/scripts/hooks/json-helper.cjs +44 -2
- package/src/assets/scripts/hooks/lib/curation-store.cjs +82 -20
- package/src/assets/scripts/hooks/lib/render-decisions.cjs +9 -1
- package/src/assets/scripts/hooks/lib/tracked-areas.cjs +226 -33
- package/src/assets/scripts/hooks/memory-permission +10 -2
- package/src/assets/scripts/hooks/memory-worker +11 -0
- package/src/assets/scripts/hooks/pre-compact-memory +11 -0
- package/src/assets/scripts/hooks/queue-append +218 -1
- package/src/assets/scripts/hooks/session-start-context +89 -37
- package/src/assets/scripts/hooks/session-start-memory +39 -0
- package/src/assets/scripts/pr-evidence.cjs +5 -2
- package/src/assets/scripts/resolve-settings.cjs +244 -30
- package/src/assets/scripts/verify-evidence.cjs +307 -75
- package/src/assets/skills/agent-references/SKILL.md +7 -1
- package/src/assets/skills/agent-references/references/commands/implement-levels.md +6 -4
- package/src/assets/skills/agent-references/references/commands/resolve-levels.md +3 -2
- package/src/assets/skills/agent-references/references/synthesize/review.md +4 -4
- package/src/assets/skills/agent-references/references/triage/severity-tiers.md +43 -0
- package/src/assets/skills/agent-references/references/validate/passed-alone.md +14 -0
|
@@ -8,8 +8,11 @@ import { writeSettingsFileAtomic } from '../../core/fs-atomic.js';
|
|
|
8
8
|
import { discoverProjectGitRoots } from '../../targets/claude-code/post-install.js';
|
|
9
9
|
import { getGitRoot } from '../../core/git.js';
|
|
10
10
|
import { firstSymbolicLink } from '../../core/linked-path.js';
|
|
11
|
+
import { pooled } from '../../core/pool.js';
|
|
11
12
|
import { getMemoryDir, getPendingTurnsPath, getPendingTurnsProcessingPath, } from '../../core/project-paths.js';
|
|
12
13
|
import { drainQueueFiles, formatRefusedDrain } from '../../core/queue-drain.js';
|
|
14
|
+
import { AREA_PAUSE_NOTICE } from '../../core/area-pause-notice.js';
|
|
15
|
+
import { probeTrackedArea } from '../../core/tracked-areas.js';
|
|
13
16
|
import { HOOKS_DIR_SUFFIX, devflowHookOwner, endsWithAny, ensureHook, hasHook, removeHooks, runHookCommand, runHookSuffix, } from '../../targets/claude-code/hooks.js';
|
|
14
17
|
import { readMachineFeature, writeMachineFeature } from '../../core/feature-switch.js';
|
|
15
18
|
import { loadSettingsModule, narrowedSwitchLabel, personalConfigTrackedWarning } from '../../core/evidence-policy.js';
|
|
@@ -159,21 +162,42 @@ export function convergeMemoryHooks(settingsJson, enabled, devflowDir) {
|
|
|
159
162
|
const cleaned = removeMemoryHooks(settingsJson);
|
|
160
163
|
return enabled ? addMemoryHooks(cleaned, devflowDir) : cleaned;
|
|
161
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Why the memory area at `projectRoot` is paused, or null when git tracks nothing in the
|
|
167
|
+
* memory folder there. The area is paused when git tracks files in the memory folder, or
|
|
168
|
+
* a `.git` entry stands and git did not answer (`unknown`); a root with no `.git` entry
|
|
169
|
+
* makes no git call. The root is the checkout's toplevel, where the memory hooks work.
|
|
170
|
+
*/
|
|
171
|
+
async function memoryPauseReason(projectRoot) {
|
|
172
|
+
const { answer } = await probeTrackedArea(projectRoot, 'memory');
|
|
173
|
+
return answer === 'untracked' ? null : answer;
|
|
174
|
+
}
|
|
162
175
|
/**
|
|
163
176
|
* Drain a project's pending memory queue (and a claimed batch) so stale turns
|
|
164
177
|
* are not processed when memory is next switched on. Shared by `devflow init
|
|
165
|
-
* --no-memory` and `devflow memory --disable`.
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
178
|
+
* --no-memory` and `devflow memory --disable`. Deletes nothing, and answers
|
|
179
|
+
* `skipped`, when git tracks files in the memory folder or a `.git` entry stands and
|
|
180
|
+
* git does not answer: a folder that git tracks is the repository's content. Refused,
|
|
181
|
+
* deleting nothing, when `.devflow` or `.devflow/memory` under `projectRoot` is a
|
|
182
|
+
* symbolic link (D-CLI-NO-SYMLINK). ENOENT-tolerant; any other error propagates to the
|
|
183
|
+
* command boundary, like drainCurationQueue.
|
|
169
184
|
*/
|
|
170
185
|
export async function drainMemoryQueue(projectRoot) {
|
|
186
|
+
const skipped = await memoryPauseReason(projectRoot);
|
|
187
|
+
if (skipped !== null)
|
|
188
|
+
return { drained: false, skipped };
|
|
171
189
|
const memoryDir = getMemoryDir(projectRoot);
|
|
172
190
|
return drainQueueFiles([path.dirname(memoryDir), memoryDir], [
|
|
173
191
|
getPendingTurnsPath(projectRoot),
|
|
174
192
|
getPendingTurnsProcessingPath(projectRoot),
|
|
175
193
|
]);
|
|
176
194
|
}
|
|
195
|
+
/** The line a caller prints for a memory drain that deleted nothing: the fixed notice of a paused area, or the refusal at a link. */
|
|
196
|
+
export function formatMemoryNotDrained(drain) {
|
|
197
|
+
if (!('skipped' in drain))
|
|
198
|
+
return formatRefusedDrain('memory', drain.linkedFolder);
|
|
199
|
+
return `The memory queue was not drained. ${AREA_PAUSE_NOTICE.memory[drain.skipped]}`;
|
|
200
|
+
}
|
|
177
201
|
/**
|
|
178
202
|
* Returns true if the given project root contains a `.devflow/memory/` directory.
|
|
179
203
|
* Treats unexpected errors (e.g. EACCES) as absent to avoid false positives.
|
|
@@ -200,15 +224,23 @@ export async function filterProjectsWithMemory(gitRoots) {
|
|
|
200
224
|
const checks = await Promise.all(gitRoots.map(async (root) => ({ root, has: await hasMemoryDir(root) })));
|
|
201
225
|
return checks.filter((c) => c.has).map((c) => c.root);
|
|
202
226
|
}
|
|
227
|
+
/** At most this many projects are checked and cleaned at once, so `memory --clear` starts few git processes. */
|
|
228
|
+
export const CLEAN_QUEUE_POOL_LIMIT = 8;
|
|
203
229
|
/**
|
|
204
230
|
* Clean up memory queue files from the given project paths.
|
|
205
231
|
* Skips projects where the background updater lock is held to avoid data loss,
|
|
206
|
-
*
|
|
207
|
-
* `.
|
|
208
|
-
*
|
|
232
|
+
* leaves a project whose memory area is paused alone (git tracks files in the memory
|
|
233
|
+
* folder, or a `.git` entry stands and git did not answer; `paused` names each such
|
|
234
|
+
* project with the reason), and refuses, deleting nothing there, a project whose
|
|
235
|
+
* `.devflow` or `.devflow/memory` is a symbolic link (D-CLI-NO-SYMLINK); `refused` names
|
|
236
|
+
* each such link. At most {@link CLEAN_QUEUE_POOL_LIMIT} projects are handled at once.
|
|
237
|
+
* Returns the count of projects from which at least one file was removed.
|
|
209
238
|
*/
|
|
210
239
|
export async function cleanQueueFiles(projectPaths) {
|
|
211
|
-
const
|
|
240
|
+
const settled = await pooled(projectPaths, CLEAN_QUEUE_POOL_LIMIT, async (project) => {
|
|
241
|
+
const reason = await memoryPauseReason(project);
|
|
242
|
+
if (reason !== null)
|
|
243
|
+
return { paused: reason, project };
|
|
212
244
|
const memDir = getMemoryDir(project);
|
|
213
245
|
let linkedFolder;
|
|
214
246
|
try {
|
|
@@ -234,10 +266,16 @@ export async function cleanQueueFiles(projectPaths) {
|
|
|
234
266
|
fs.unlink(getPendingTurnsProcessingPath(project)).then(() => true).catch(() => false),
|
|
235
267
|
]);
|
|
236
268
|
return (q || pr) ? { cleaned: project } : null;
|
|
237
|
-
})
|
|
269
|
+
});
|
|
270
|
+
const results = settled.map((entry) => {
|
|
271
|
+
if (entry.status === 'rejected')
|
|
272
|
+
throw entry.reason;
|
|
273
|
+
return entry.value;
|
|
274
|
+
});
|
|
238
275
|
const cleanedProjects = results.flatMap((r) => (r !== null && 'cleaned' in r ? [r.cleaned] : []));
|
|
239
276
|
const refused = results.flatMap((r) => (r !== null && 'refused' in r ? [r.refused] : []));
|
|
240
|
-
|
|
277
|
+
const paused = results.flatMap((r) => (r !== null && 'paused' in r ? [{ project: r.project, reason: r.paused }] : []));
|
|
278
|
+
return { cleaned: cleanedProjects.length, projects: cleanedProjects, refused, paused };
|
|
241
279
|
}
|
|
242
280
|
export const memoryCommand = new Command('memory')
|
|
243
281
|
.description('Enable, disable, or clean up working memory (session context preservation)')
|
|
@@ -297,10 +335,13 @@ export const memoryCommand = new Command('memory')
|
|
|
297
335
|
}
|
|
298
336
|
targets = scope === 'local' && currentProject ? [currentProject] : allProjects;
|
|
299
337
|
}
|
|
300
|
-
const { cleaned, projects: cleanedProjects, refused } = await cleanQueueFiles(targets);
|
|
338
|
+
const { cleaned, projects: cleanedProjects, refused, paused } = await cleanQueueFiles(targets);
|
|
301
339
|
for (const project of cleanedProjects) {
|
|
302
340
|
p.log.info(color.dim(`Cleaned: ${project}`));
|
|
303
341
|
}
|
|
342
|
+
for (const { project, reason } of paused) {
|
|
343
|
+
p.log.warn(`The memory queue of ${project} was not cleaned. ${AREA_PAUSE_NOTICE.memory[reason]}`);
|
|
344
|
+
}
|
|
304
345
|
for (const linkedFolder of refused) {
|
|
305
346
|
p.log.warn(formatRefusedDrain('memory', linkedFolder));
|
|
306
347
|
}
|
|
@@ -340,6 +381,12 @@ export const memoryCommand = new Command('memory')
|
|
|
340
381
|
const narrowed = enabled ? narrowedSwitchLabel(settingsModule, { dir: process.cwd() }, 'memory') : null;
|
|
341
382
|
if (narrowed !== null)
|
|
342
383
|
p.log.info(`Effective here: ${color.yellow(narrowed)}`);
|
|
384
|
+
// A paused memory area (git tracks files in the memory folder, or did not answer):
|
|
385
|
+
// the fixed notice, from the checkout's toplevel, where the memory hooks work. The
|
|
386
|
+
// current directory stands in outside a git work tree, as it does for the settings line.
|
|
387
|
+
const paused = await memoryPauseReason((await getGitRoot()) ?? process.cwd());
|
|
388
|
+
if (paused !== null)
|
|
389
|
+
p.log.info(AREA_PAUSE_NOTICE.memory[paused]);
|
|
343
390
|
const trackedWarning = personalConfigTrackedWarning(settingsModule, { dir: process.cwd() });
|
|
344
391
|
if (trackedWarning !== null)
|
|
345
392
|
p.log.warn(trackedWarning);
|
|
@@ -380,7 +427,7 @@ export const memoryCommand = new Command('memory')
|
|
|
380
427
|
if (gitRoot) {
|
|
381
428
|
const drain = await drainMemoryQueue(gitRoot);
|
|
382
429
|
if (!drain.drained)
|
|
383
|
-
p.log.warn(
|
|
430
|
+
p.log.warn(formatMemoryNotDrained(drain));
|
|
384
431
|
}
|
|
385
432
|
p.log.success('Working memory disabled in every project');
|
|
386
433
|
});
|
|
@@ -32,7 +32,8 @@ import { stripDevflowTeammateModeFromJson } from '../../core/teammate-mode-clean
|
|
|
32
32
|
import { getPackageRoot, isContainedIn } from '../../core/paths.js';
|
|
33
33
|
import { firstSymbolicLink } from '../../core/linked-path.js';
|
|
34
34
|
import { MANIFEST_LOCK_NAME, MANIFEST_LOCK_STALE_MARK } from '../../core/manifest-lock.js';
|
|
35
|
-
import { CURATION_TUNING_FILE_NAME, LEGACY_NAMES, MOVE_JOURNAL_SUFFIX, MOVE_LOCK_PREFIX, MOVE_LOCK_SUFFIX } from '../../core/project-paths.js';
|
|
35
|
+
import { CURATION_DIR_NAME, CURATION_TUNING_FILE_NAME, LEGACY_NAMES, MOVE_JOURNAL_SUFFIX, MOVE_LOCK_PREFIX, MOVE_LOCK_SUFFIX, getMemoryDir } from '../../core/project-paths.js';
|
|
36
|
+
import { probeTrackedArea } from '../../core/tracked-areas.js';
|
|
36
37
|
import { restampInstalledCommands } from '../../targets/claude-code/language-stamp.js';
|
|
37
38
|
import { installCommandsAndAgents } from '../../targets/claude-code/installer.js';
|
|
38
39
|
/**
|
|
@@ -285,20 +286,66 @@ const TRACKED_ENTRIES = DEVFLOW_TRACKED_PATHS.map((tracked) => ({
|
|
|
285
286
|
name: tracked.replace(/\/$/, ''),
|
|
286
287
|
isDir: tracked.endsWith('/'),
|
|
287
288
|
}));
|
|
289
|
+
/** The memory folder's name under `.devflow/`, by the name the path helper gives it. */
|
|
290
|
+
const MEMORY_FOLDER_NAME = path.basename(getMemoryDir(path.sep));
|
|
291
|
+
/**
|
|
292
|
+
* The data area an entry under `.devflow/` belongs to, or null. The curation area holds the
|
|
293
|
+
* curation folder, the old ledger folder and the backup folders; the memory area holds the
|
|
294
|
+
* memory folder. Decided by name alone, whatever the kind of entry, and without regard to
|
|
295
|
+
* ASCII letter case, as the tracked-areas check matches them.
|
|
296
|
+
*/
|
|
297
|
+
function projectDataAreaOf(name) {
|
|
298
|
+
const lower = name.toLowerCase();
|
|
299
|
+
if (lower === CURATION_DIR_NAME || lower === LEGACY_NAMES.folder || lower.startsWith(LEGACY_NAMES.backupPrefix))
|
|
300
|
+
return 'curation';
|
|
301
|
+
if (lower === MEMORY_FOLDER_NAME)
|
|
302
|
+
return 'memory';
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
288
305
|
/**
|
|
289
306
|
* Split the entries under a repository's `.devflow/` into what a confirmed cleanup
|
|
290
307
|
* removes and what it keeps (D-UNINSTALL-CARVE-OUT). An entry is kept only when both
|
|
291
308
|
* its name and its kind match a tracked path, so a stray FILE named `features` is
|
|
292
|
-
* not mistaken for the tracked directory.
|
|
309
|
+
* not mistaken for the tracked directory. An entry of a paused data area (`pausedAreas`:
|
|
310
|
+
* git tracks files in the area's folders, or did not answer) is kept too, in
|
|
311
|
+
* `keepPaused`. PURE — all three lists sorted by name.
|
|
293
312
|
*/
|
|
294
|
-
export function partitionProjectData(entries) {
|
|
313
|
+
export function partitionProjectData(entries, pausedAreas = new Set()) {
|
|
295
314
|
const isTracked = (entry) => TRACKED_ENTRIES.some((t) => t.name === entry.name && t.isDir === entry.isDir);
|
|
315
|
+
const isPaused = (entry) => {
|
|
316
|
+
const area = projectDataAreaOf(entry.name);
|
|
317
|
+
return area !== null && pausedAreas.has(area);
|
|
318
|
+
};
|
|
296
319
|
const byName = (a, b) => a.name.localeCompare(b.name);
|
|
297
320
|
return {
|
|
298
|
-
remove: entries.filter((e) => !isTracked(e)).sort(byName),
|
|
321
|
+
remove: entries.filter((e) => !isTracked(e) && !isPaused(e)).sort(byName),
|
|
299
322
|
keep: entries.filter(isTracked).sort(byName),
|
|
323
|
+
keepPaused: entries.filter((e) => !isTracked(e) && isPaused(e)).sort(byName),
|
|
300
324
|
};
|
|
301
325
|
}
|
|
326
|
+
/** The check's own answer, from the package's own copy of it. */
|
|
327
|
+
const probeProjectDataArea = async (root, area) => (await probeTrackedArea(root, area)).answer;
|
|
328
|
+
/**
|
|
329
|
+
* The data areas that hold an entry in `entries` and are paused at `gitRoot`: git tracks
|
|
330
|
+
* files in the area's folders, or a `.git` entry stands and git did not answer. An area
|
|
331
|
+
* with no entry is not asked, and a root with no `.git` entry makes no git call. A probe
|
|
332
|
+
* that fails to answer counts as `unknown`, so the area is kept.
|
|
333
|
+
*/
|
|
334
|
+
async function pausedProjectDataAreas(gitRoot, entries, probe) {
|
|
335
|
+
const present = new Set(entries.flatMap((entry) => {
|
|
336
|
+
const area = projectDataAreaOf(entry.name);
|
|
337
|
+
return area === null ? [] : [area];
|
|
338
|
+
}));
|
|
339
|
+
const answers = await Promise.all([...present].map(async (area) => {
|
|
340
|
+
try {
|
|
341
|
+
return [area, await probe(gitRoot, area)];
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
return [area, 'unknown'];
|
|
345
|
+
}
|
|
346
|
+
}));
|
|
347
|
+
return new Set(answers.flatMap(([area, answer]) => (answer === 'untracked' ? [] : [area])));
|
|
348
|
+
}
|
|
302
349
|
/**
|
|
303
350
|
* Resolve the project-data step's target: `<gitRoot>/.devflow`, partitioned.
|
|
304
351
|
*
|
|
@@ -312,6 +359,12 @@ export function partitionProjectData(entries) {
|
|
|
312
359
|
* A `.devflow` that is a symbolic link to anywhere else is skipped too, and never
|
|
313
360
|
* followed: its target is a directory devflow cannot prove it wrote, so a
|
|
314
361
|
* confirmed cleanup must not empty it — nor unlink a link the user made.
|
|
362
|
+
*
|
|
363
|
+
* A folder that git tracks is the repository's content, not devflow's data. The
|
|
364
|
+
* curation area (the curation folder, the old ledger folder and the backup folders)
|
|
365
|
+
* and the memory area (the memory folder) are each asked of the tracked-areas check at
|
|
366
|
+
* the git root, when an entry of the area stands. An area that git tracks files in, or
|
|
367
|
+
* that git did not answer for, moves its entries from the removal list to `keepPaused`.
|
|
315
368
|
*/
|
|
316
369
|
export async function resolveProjectDataPlan(opts) {
|
|
317
370
|
if (opts.gitRoot === null)
|
|
@@ -335,8 +388,10 @@ export async function resolveProjectDataPlan(opts) {
|
|
|
335
388
|
catch {
|
|
336
389
|
return { kind: 'skip', reason: 'absent' };
|
|
337
390
|
}
|
|
338
|
-
const
|
|
339
|
-
|
|
391
|
+
const entries = dirents.map((d) => ({ name: d.name, isDir: d.isDirectory() }));
|
|
392
|
+
const paused = await pausedProjectDataAreas(opts.gitRoot, entries, opts.probe ?? probeProjectDataArea);
|
|
393
|
+
const { remove, keep, keepPaused } = partitionProjectData(entries, paused);
|
|
394
|
+
return { kind: 'plan', plan: { dir, remove, keep, keepPaused } };
|
|
340
395
|
}
|
|
341
396
|
/**
|
|
342
397
|
* The line that tells the user why the project-data step was skipped, or null
|
|
@@ -366,15 +421,21 @@ function entryLabel(entry) {
|
|
|
366
421
|
function entryList(entries) {
|
|
367
422
|
return entries.length === 0 ? '(none)' : entries.map(entryLabel).join(', ');
|
|
368
423
|
}
|
|
424
|
+
/** Why the entries of a data area stay, said beside a list of them. */
|
|
425
|
+
const KEEP_PAUSED_REASON = 'git tracks them, or git did not answer';
|
|
426
|
+
/** Why one entry of a data area stays, said beside it. */
|
|
427
|
+
const KEEP_PAUSED_REASON_ONE = 'git tracks it, or git did not answer';
|
|
369
428
|
/**
|
|
370
429
|
* The lines shown before the project-data confirm: what is removed and what is
|
|
371
|
-
* kept
|
|
430
|
+
* kept, and, only where there are such entries, what is kept because git tracks them
|
|
431
|
+
* or did not answer. PURE.
|
|
372
432
|
*/
|
|
373
433
|
export function formatProjectDataPlan(plan) {
|
|
374
434
|
return [
|
|
375
435
|
`Project data in ${plan.dir}/:`,
|
|
376
436
|
` Remove: ${entryList(plan.remove)}`,
|
|
377
437
|
` Keep (shared via git): ${entryList(plan.keep)}`,
|
|
438
|
+
...(plan.keepPaused.length === 0 ? [] : [` Keep (${KEEP_PAUSED_REASON}): ${entryList(plan.keepPaused)}`]),
|
|
378
439
|
];
|
|
379
440
|
}
|
|
380
441
|
/**
|
|
@@ -946,6 +1007,9 @@ export async function runDryRunPhase(opts) {
|
|
|
946
1007
|
for (const entry of projectData.plan.remove) {
|
|
947
1008
|
extras.push(`${path.join(projectData.plan.dir, entryLabel(entry))} (if confirmed)`);
|
|
948
1009
|
}
|
|
1010
|
+
for (const entry of projectData.plan.keepPaused) {
|
|
1011
|
+
extras.push(`${path.join(projectData.plan.dir, entryLabel(entry))} (kept: ${KEEP_PAUSED_REASON_ONE})`);
|
|
1012
|
+
}
|
|
949
1013
|
}
|
|
950
1014
|
else {
|
|
951
1015
|
const skipped = formatProjectDataSkip(projectData.reason, projectRoot);
|
|
@@ -1251,7 +1315,9 @@ export async function runFullPhaseForScope(opts) {
|
|
|
1251
1315
|
async function runProjectDataStep(plan, gates) {
|
|
1252
1316
|
const shown = `${plan.dir}/`;
|
|
1253
1317
|
if (plan.remove.length === 0) {
|
|
1254
|
-
p.log.info(
|
|
1318
|
+
p.log.info(plan.keepPaused.length === 0
|
|
1319
|
+
? `${shown} preserved (holds only files shared via git)`
|
|
1320
|
+
: `${shown} preserved (holds only files shared via git, and ${entryList(plan.keepPaused)}, which stay: ${KEEP_PAUSED_REASON})`);
|
|
1255
1321
|
return;
|
|
1256
1322
|
}
|
|
1257
1323
|
if (gates.keepDocs) {
|
|
@@ -1287,7 +1353,7 @@ async function runProjectDataStep(plan, gates) {
|
|
|
1287
1353
|
failed.push(`${entryLabel(entry)} (${err.code ?? err.message})`);
|
|
1288
1354
|
}
|
|
1289
1355
|
}
|
|
1290
|
-
if (plan.keep.length === 0 && failed.length === 0) {
|
|
1356
|
+
if (plan.keep.length === 0 && plan.keepPaused.length === 0 && failed.length === 0) {
|
|
1291
1357
|
// Nothing tracked was there: drop the now-empty directory. rmdir refuses a
|
|
1292
1358
|
// directory something wrote into meanwhile, which is then left in place.
|
|
1293
1359
|
await fs.rmdir(plan.dir).catch(() => undefined);
|
|
@@ -1298,6 +1364,8 @@ async function runProjectDataStep(plan, gates) {
|
|
|
1298
1364
|
p.log.warn(`Could not remove from ${shown}: ${failed.join(', ')}`);
|
|
1299
1365
|
if (plan.keep.length > 0)
|
|
1300
1366
|
p.log.info(`Kept: ${entryList(plan.keep)}`);
|
|
1367
|
+
if (plan.keepPaused.length > 0)
|
|
1368
|
+
p.log.info(`Kept: ${entryList(plan.keepPaused)} (${KEEP_PAUSED_REASON})`);
|
|
1301
1369
|
}
|
|
1302
1370
|
/**
|
|
1303
1371
|
* CLEANUP PHASE: post-loop extras run only on full uninstall.
|
|
@@ -180,13 +180,13 @@ If no tool produced findings: set `STATIC_FINDINGS` to `(none)`.
|
|
|
180
180
|
|
|
181
181
|
#### Decisions Index
|
|
182
182
|
|
|
183
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
183
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
184
184
|
|
|
185
185
|
```bash
|
|
186
186
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
189
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
190
190
|
|
|
191
191
|
The accepted line is the only source of these values.
|
|
192
192
|
|
|
@@ -35,13 +35,13 @@ Run a comprehensive code review of the current branch by spawning parallel revie
|
|
|
35
35
|
|
|
36
36
|
**Produces:** COMPLIANCE_ACTIVE, COMPLIANCE_FRAMEWORKS, GATE_LEVEL
|
|
37
37
|
|
|
38
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
38
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
44
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
45
45
|
|
|
46
46
|
The accepted line is the only source of these values.
|
|
47
47
|
|
|
@@ -136,11 +136,11 @@ For each worktree:
|
|
|
136
136
|
**Produces:** PRIOR_RESOLUTIONS, CYCLE_NUMBER
|
|
137
137
|
**Requires:** BRANCH_INFO
|
|
138
138
|
|
|
139
|
-
For each worktree
|
|
140
|
-
1. List timestamped directories
|
|
141
|
-
2. Iterate once:
|
|
139
|
+
For each worktree:
|
|
140
|
+
1. List the timestamped directories: `ls -1d {worktree}/.devflow/docs/reviews/{branch-slug}/20* 2>/dev/null | sort -r`
|
|
141
|
+
2. Iterate once: count each directory containing `resolution-summary.md` as CYCLE_NUMBER; capture the first (newest) as PRIOR_DIR.
|
|
142
142
|
3. If CYCLE_NUMBER = 0: set PRIOR_RESOLUTIONS=(none), CYCLE_NUMBER=1, proceed.
|
|
143
|
-
4. Otherwise: set CYCLE_NUMBER = count + 1. Read `{PRIOR_DIR}/resolution-summary.md` as PRIOR_RESOLUTIONS.
|
|
143
|
+
4. Otherwise: set CYCLE_NUMBER = count + 1. Read `{PRIOR_DIR}/resolution-summary.md` as PRIOR_RESOLUTIONS minus each section from a heading line (fenced or not) with the word `Private` (any case) not followed by a letter or digit, to the next unfenced heading with as many `#` as its start or fewer, else at end of file. Close any fence it leaves open. When unsure, cut more; if the cut fails, PRIOR_RESOLUTIONS=(none).
|
|
144
144
|
5. If `--full`: still load PRIOR_RESOLUTIONS.
|
|
145
145
|
|
|
146
146
|
#### Step 0e-ii: Convergence Assessment
|
|
@@ -158,7 +158,7 @@ MAX_REVIEW_CYCLES = 10
|
|
|
158
158
|
- `deferred_count` = the Deferred row value (= FIX_SEPARATE + TECH_DEBT); By Design and Escalated are excluded from the fp_ratio denominator
|
|
159
159
|
- fp_ratio = fp_count / (fp_count + fixed_count + deferred_count)
|
|
160
160
|
- If denominator = 0: fp_ratio = 0, skip warning
|
|
161
|
-
- If parsing fails: fp_ratio = 0, skip warning; note in output: "Warning: Could not parse Statistics table
|
|
161
|
+
- If parsing fails: fp_ratio = 0, skip warning; note in output: "Warning: Could not parse Statistics table. Convergence tracking degraded."
|
|
162
162
|
3. If fp_ratio > 0.7 AND CYCLE_NUMBER >= 3:
|
|
163
163
|
Warn in output: "⚠️ Convergence: {ratio}% false positives in cycle {N-1}. Consider merging or manual inspection."
|
|
164
164
|
Continue with review.
|
|
@@ -453,7 +453,7 @@ Follow devflow:apply-feature-knowledge for FEATURE_KNOWLEDGE — feature-specifi
|
|
|
453
453
|
IMPORTANT: Write report to {worktree_path}/.devflow/docs/reviews/{branch-slug}/{timestamp}/{focus}.md using Write tool"
|
|
454
454
|
```
|
|
455
455
|
|
|
456
|
-
In multi-worktree mode, process worktrees **sequentially**: Phases 1-4 for
|
|
456
|
+
In multi-worktree mode, process worktrees **sequentially**: Phases 1-4 for each.
|
|
457
457
|
|
|
458
458
|
### Phase 3: Synthesis → Review Comment (Sequential)
|
|
459
459
|
|
|
@@ -488,7 +488,7 @@ CYCLE_NUMBER: {cycle_number}
|
|
|
488
488
|
REVIEW_TIMESTAMP: {timestamp}
|
|
489
489
|
REVIEW_PUBLICATION: {REVIEW_PUBLICATION}
|
|
490
490
|
WORKTREE_PATH: {worktree_path} (omit if cwd)
|
|
491
|
-
Posts the consolidated review-summary comment (marker-deduped
|
|
491
|
+
Posts the consolidated review-summary comment (marker-deduped on the cycle+timestamp pair)."
|
|
492
492
|
```
|
|
493
493
|
|
|
494
494
|
### Phase 4: Write Review Head Marker & Report
|
|
@@ -536,7 +536,7 @@ Per worktree, after successful completion:
|
|
|
536
536
|
| Case | Handling |
|
|
537
537
|
|------|----------|
|
|
538
538
|
| `--full` in multi-worktree mode | Applies to all worktrees (global modifier). It sets the diff range, never the gate level |
|
|
539
|
-
| Review comment already posted | Git agent matches its own marker on the `{cycle, timestamp}` pair → skip silently (D7)
|
|
539
|
+
| Review comment already posted | Git agent matches its own marker on the `{cycle, timestamp}` pair → skip silently (D7) |
|
|
540
540
|
| Docs-only diff | Its Step 1.1 set, narrowed by level |
|
|
541
541
|
| Tests-only diff | Its Step 1.1 set, narrowed by level |
|
|
542
542
|
| Lockfile-only diff | Its Step 1.1 set, narrowed by level |
|
|
@@ -545,7 +545,7 @@ Per worktree, after successful completion:
|
|
|
545
545
|
| A file moved across classes | `--no-renames` lists both paths, so a code path makes the diff `code` |
|
|
546
546
|
| Path listing above about 40 lines | Read in ranges (Step 1.1) |
|
|
547
547
|
| Language files changed, plugin not installed | The focus is absent from the stamped line: not spawned |
|
|
548
|
-
| `reviewPublication: off` | Git agent skips posting the review comment (OFF) — except that, only when `EVIDENCE_POLICY` is `required`, Step 0f passes `stub` and a counts-only STUB comment posts |
|
|
548
|
+
| `reviewPublication: off` | Git agent skips posting the review comment (OFF) — except that, only when `EVIDENCE_POLICY` is `required`, Step 0f passes `stub` and a counts-only STUB comment posts unless no public text remains |
|
|
549
549
|
|
|
550
550
|
## Backwards Compatibility
|
|
551
551
|
|
package/dist/commands/debug.md
CHANGED
|
@@ -32,13 +32,13 @@ $ARGUMENTS
|
|
|
32
32
|
|
|
33
33
|
**Produces:** DECISIONS_CONTEXT
|
|
34
34
|
|
|
35
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
35
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
41
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
42
42
|
|
|
43
43
|
The accepted line is the only source of these values.
|
|
44
44
|
|
|
@@ -77,13 +77,13 @@ When a ticket requires multiple sequential Code agent phases, each Code agent ap
|
|
|
77
77
|
|
|
78
78
|
### Settings line
|
|
79
79
|
|
|
80
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
80
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
86
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
87
87
|
|
|
88
88
|
The accepted line is the only source of these values.
|
|
89
89
|
|
|
@@ -77,13 +77,13 @@ When a ticket requires multiple sequential Code agent phases, each Code agent ap
|
|
|
77
77
|
|
|
78
78
|
### Settings line
|
|
79
79
|
|
|
80
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
80
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
86
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
87
87
|
|
|
88
88
|
The accepted line is the only source of these values.
|
|
89
89
|
|
|
@@ -77,13 +77,13 @@ When a ticket requires multiple sequential Code agent phases, each Code agent ap
|
|
|
77
77
|
|
|
78
78
|
### Settings line
|
|
79
79
|
|
|
80
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
80
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
86
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
87
87
|
|
|
88
88
|
The accepted line is the only source of these values.
|
|
89
89
|
|
|
@@ -77,13 +77,13 @@ When a ticket requires multiple sequential Code agent phases, each Code agent ap
|
|
|
77
77
|
|
|
78
78
|
### Settings line
|
|
79
79
|
|
|
80
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
80
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
84
84
|
```
|
|
85
85
|
|
|
86
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
86
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
87
87
|
|
|
88
88
|
The accepted line is the only source of these values.
|
|
89
89
|
|
package/dist/commands/explore.md
CHANGED
|
@@ -32,13 +32,13 @@ $ARGUMENTS
|
|
|
32
32
|
|
|
33
33
|
**Produces:** DECISIONS_CONTEXT
|
|
34
34
|
|
|
35
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
35
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
41
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
42
42
|
|
|
43
43
|
The accepted line is the only source of these values.
|
|
44
44
|
|
|
@@ -144,13 +144,13 @@ node "$HOME/.devflow/scripts/verify-evidence.cjs" render --plan "{worktree}/.dev
|
|
|
144
144
|
|
|
145
145
|
- `EVIDENCE_FILE` — `{worktree}/.devflow/docs/evidence-{branch_slug}.md`, its `## Evidence Exceptions` section now a byte copy of `PR_EXCEPTIONS` (absent when that is `(none)`).
|
|
146
146
|
|
|
147
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
147
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
148
148
|
|
|
149
149
|
```bash
|
|
150
150
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
151
151
|
```
|
|
152
152
|
|
|
153
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
153
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
154
154
|
|
|
155
155
|
The accepted line is the only source of these values.
|
|
156
156
|
|
package/dist/commands/plan.md
CHANGED
|
@@ -108,13 +108,13 @@ If the user says "skip" or "just proceed" — skip remaining questions, present
|
|
|
108
108
|
**Produces:** SKIM_CONTEXT, DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES, GATE_LEVEL
|
|
109
109
|
**Requires:** CONFIRMED_SCOPE
|
|
110
110
|
|
|
111
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
111
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
112
112
|
|
|
113
113
|
```bash
|
|
114
114
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
115
115
|
```
|
|
116
116
|
|
|
117
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
117
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
118
118
|
|
|
119
119
|
The accepted line is the only source of these values.
|
|
120
120
|
|
package/dist/commands/release.md
CHANGED
|
@@ -52,13 +52,13 @@ Read `.release/RELEASE-FLOW.md`:
|
|
|
52
52
|
|
|
53
53
|
**Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE, FEATURE_KNOWLEDGE_RULES
|
|
54
54
|
|
|
55
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
55
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
56
56
|
|
|
57
57
|
```bash
|
|
58
58
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
61
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
62
62
|
|
|
63
63
|
The accepted line is the only source of these values.
|
|
64
64
|
|
|
@@ -41,13 +41,13 @@ git -C "{start}" rev-parse --show-toplevel
|
|
|
41
41
|
|
|
42
42
|
and using its one-line output. If the command fails (outside a git repository), `{worktree}` is the start directory itself. Every docs path below is written `{worktree}/.devflow/docs/…`; a repo-relative docs path handed to an agent always travels with a `WORKTREE_PATH` naming the checkout it is relative to.
|
|
43
43
|
|
|
44
|
-
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root
|
|
44
|
+
**Resolve the settings line** once per worktree root, reusing a line this run already resolved for the same root. `{root}` is the worktree the values are for — the repository root in a one-worktree run:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
node "$HOME/.devflow/scripts/resolve-settings.cjs" "{root}" 2>/dev/null; echo "exit=$?"
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=
|
|
50
|
+
Accept the output only when it is exactly two lines: `exit=0` last and, before it, one line of the form `TRACKER=<github|jira|linear> TRACKER_SOURCE=<project|personal|machine|default> TRACKER_WARN=<none|mismatch|invalid> SITE=<none|https://<host>> KEY=<none|<key>> REVIEW_PUBLICATION=<off|auto|full> COMPLIANCE=<off|generic|<id>[,<id>…]> MEMORY=<on|off> CURATION=<on|off> KNOWLEDGE=<on|off> GATE_LEVEL=<full|standard|lean>` — these fields, in this order, nothing else, where `<host>` is a lowercase dotted host name alone, `<key>` is 2–10 of `A-Z`, `0-9` and `_` starting with a letter, and each `<id>` is one of `gdpr`, `hipaa`, `pci-dss`, `soc2`, `iso-27001`, `sox`. **Anything else** (a non-zero exit, no line, extra text, or a missing, reordered or unlisted field or value) ⇒ use `TRACKER=github TRACKER_SOURCE=default TRACKER_WARN=invalid SITE=none KEY=none REVIEW_PUBLICATION=off COMPLIANCE=generic MEMORY=off CURATION=off KNOWLEDGE=off GATE_LEVEL=full` instead.
|
|
51
51
|
|
|
52
52
|
The accepted line is the only source of these values.
|
|
53
53
|
|