@deftai/directive-core 0.95.0 → 0.97.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/dist/cache/archive.d.ts +134 -0
- package/dist/cache/archive.js +636 -0
- package/dist/cache/index.d.ts +1 -0
- package/dist/cache/index.js +1 -0
- package/dist/cache/main.js +298 -1
- package/dist/check/gate-lists.js +8 -0
- package/dist/consumer-check-contract/evaluate.d.ts +124 -0
- package/dist/consumer-check-contract/evaluate.js +699 -0
- package/dist/consumer-check-contract/index.d.ts +5 -0
- package/dist/consumer-check-contract/index.js +5 -0
- package/dist/content-contracts/skills/helpers.d.ts +1 -1
- package/dist/content-contracts/skills/helpers.js +1 -0
- package/dist/delivery-attempt/disk-begin.d.ts +51 -0
- package/dist/delivery-attempt/disk-begin.js +68 -0
- package/dist/delivery-attempt/evaluate.d.ts +26 -0
- package/dist/delivery-attempt/evaluate.js +443 -0
- package/dist/delivery-attempt/fingerprint.d.ts +32 -0
- package/dist/delivery-attempt/fingerprint.js +100 -0
- package/dist/delivery-attempt/handoff.d.ts +25 -0
- package/dist/delivery-attempt/handoff.js +102 -0
- package/dist/delivery-attempt/index.d.ts +17 -0
- package/dist/delivery-attempt/index.js +17 -0
- package/dist/delivery-attempt/ledger.d.ts +169 -0
- package/dist/delivery-attempt/ledger.js +758 -0
- package/dist/delivery-attempt/material-delta.d.ts +38 -0
- package/dist/delivery-attempt/material-delta.js +126 -0
- package/dist/delivery-attempt/types.d.ts +210 -0
- package/dist/delivery-attempt/types.js +77 -0
- package/dist/doctor/index.d.ts +1 -0
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/main.js +12 -0
- package/dist/doctor/openclaw-soft-rebind.d.ts +26 -0
- package/dist/doctor/openclaw-soft-rebind.js +164 -0
- package/dist/hooks/dispatcher.d.ts +2 -1
- package/dist/hooks/dispatcher.js +63 -9
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/init-deposit/gitignore.js +7 -0
- package/dist/init-deposit/hygiene.d.ts +1 -1
- package/dist/init-deposit/hygiene.js +16 -4
- package/dist/init-deposit/init-deposit.js +5 -0
- package/dist/init-deposit/refresh.js +3 -0
- package/dist/init-deposit/scaffold.js +6 -5
- package/dist/parent-turn-shape/evaluate.d.ts +84 -0
- package/dist/parent-turn-shape/evaluate.js +353 -0
- package/dist/parent-turn-shape/index.d.ts +8 -0
- package/dist/parent-turn-shape/index.js +8 -0
- package/dist/pr-merge-readiness/ci-gate.d.ts +29 -1
- package/dist/pr-merge-readiness/ci-gate.js +191 -24
- package/dist/pr-merge-readiness/compute.js +10 -1
- package/dist/pr-merge-readiness/index.d.ts +2 -1
- package/dist/pr-merge-readiness/index.js +2 -1
- package/dist/pr-merge-readiness/output.js +14 -0
- package/dist/pr-merge-readiness/platform-status.d.ts +29 -0
- package/dist/pr-merge-readiness/platform-status.js +49 -0
- package/dist/pr-watch/constants.d.ts +10 -0
- package/dist/pr-watch/constants.js +12 -1
- package/dist/pr-watch/main.js +16 -1
- package/dist/pr-watch/probe.js +13 -1
- package/dist/pr-watch/types.d.ts +3 -2
- package/dist/pr-watch/watch.js +14 -7
- package/dist/review-monitor/constants.js +3 -2
- package/dist/review-monitor/tier-detection.d.ts +7 -3
- package/dist/review-monitor/tier-detection.js +18 -1
- package/dist/review-monitor/verify.js +18 -0
- package/dist/scope/index.d.ts +2 -0
- package/dist/scope/index.js +2 -0
- package/dist/scope/main.d.ts +10 -0
- package/dist/scope/main.js +109 -24
- package/dist/scope/promote-from-issue.d.ts +49 -0
- package/dist/scope/promote-from-issue.js +367 -0
- package/dist/scope/promote-path.d.ts +39 -0
- package/dist/scope/promote-path.js +105 -0
- package/dist/scope-provenance/digest.d.ts +67 -0
- package/dist/scope-provenance/digest.js +188 -0
- package/dist/scope-provenance/evaluate.d.ts +82 -0
- package/dist/scope-provenance/evaluate.js +528 -0
- package/dist/scope-provenance/index.d.ts +6 -0
- package/dist/scope-provenance/index.js +6 -0
- package/dist/session/compact-ritual.d.ts +96 -0
- package/dist/session/compact-ritual.js +237 -0
- package/dist/session/compact-ritual.spec.d.ts +2 -0
- package/dist/session/compact-ritual.spec.js +21 -0
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +2 -0
- package/dist/session/openclaw-soft-rebind-deposit.d.ts +46 -0
- package/dist/session/openclaw-soft-rebind-deposit.js +165 -0
- package/dist/swarm/routing.d.ts +4 -2
- package/dist/swarm/routing.js +26 -4
- package/dist/test-boundary/evaluate.d.ts +54 -0
- package/dist/test-boundary/evaluate.js +368 -0
- package/dist/test-boundary/index.d.ts +6 -0
- package/dist/test-boundary/index.js +6 -0
- package/dist/test-boundary/policy.d.ts +52 -0
- package/dist/test-boundary/policy.js +182 -0
- package/dist/triage/actions/index.js +62 -2
- package/dist/triage/actions/types.d.ts +8 -1
- package/dist/triage/author-filter.d.ts +51 -0
- package/dist/triage/author-filter.js +152 -0
- package/dist/triage/bootstrap/gitignore.d.ts +1 -1
- package/dist/triage/bootstrap/gitignore.js +15 -1
- package/dist/triage/classify/index.d.ts +2 -2
- package/dist/triage/classify/index.js +2 -2
- package/dist/triage/classify/label-mirror.d.ts +68 -5
- package/dist/triage/classify/label-mirror.js +261 -31
- package/dist/triage/help/registry-data.d.ts +49 -38
- package/dist/triage/help/registry-data.js +115 -40
- package/dist/triage/index.d.ts +1 -0
- package/dist/triage/index.js +1 -0
- package/dist/triage/queue/index.d.ts +1 -0
- package/dist/triage/queue/index.js +1 -0
- package/dist/triage/queue/render.d.ts +2 -0
- package/dist/triage/queue/render.js +6 -0
- package/dist/vbrief-activate/activate.js +22 -6
- package/dist/xbrief/styles.js +33 -17
- package/package.json +11 -3
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tier-1 deterministic SCM label mirror (#1423 Wave 1).
|
|
2
|
+
* Tier-1 deterministic SCM label mirror (#1423 Wave 1 + Wave 2 bootstrap).
|
|
3
3
|
*
|
|
4
4
|
* Classifies cached issues with the existing #1129 engine, then mirrors the
|
|
5
5
|
* outcome as SCM labels (dry-run default, --apply to write). Never accepts into
|
|
6
6
|
* the xBRIEF lifecycle and never writes proposed/ scopes.
|
|
7
7
|
*
|
|
8
|
+
* Wave 2 (#3125): open-only default, operator digest (totals + by state/rule/action
|
|
9
|
+
* + samples), batched rate-limit-aware apply. Bootstrap mass-triage entrypoint is
|
|
10
|
+
* `triage:classify -- --mirror` with these filters (not triage:accept).
|
|
11
|
+
*
|
|
8
12
|
* Intentionally does NOT import from ./index.js (SLizard P1 cycle). The classify
|
|
9
13
|
* engine is injected via LabelMirrorEngine / mirrorLabels() wrapper in index.ts.
|
|
10
14
|
*/
|
|
@@ -16,11 +20,18 @@ import { readPlanPolicy } from "../../policy/plan-extensions.js";
|
|
|
16
20
|
import { ScmLabelClient } from "../../vbrief-reconcile/labels.js";
|
|
17
21
|
import { isRepoMutationAllowed } from "../../vbrief-reconcile/repo-guard.js";
|
|
18
22
|
import { latestDecisions, readAuditLog } from "../actions/candidates-log.js";
|
|
23
|
+
import { authorLoginFromRawIssue, matchesAuthorFilter, } from "../author-filter.js";
|
|
19
24
|
import { resolveCandidatesLogPath } from "../cache-path.js";
|
|
20
25
|
import { iterCachedIssues } from "../summary/index.js";
|
|
21
26
|
export const DEFAULT_IDEMPOTENCY_LABEL = "triaged";
|
|
22
27
|
export const CACHE_DIR_NAME = ".deft-cache";
|
|
23
28
|
export const CACHE_SOURCE = "github-issue";
|
|
29
|
+
/** Default apply batch size for rate-limit awareness (#3125). */
|
|
30
|
+
export const DEFAULT_APPLY_BATCH_SIZE = 10;
|
|
31
|
+
/** Default delay between apply batches in ms (#3125). */
|
|
32
|
+
export const DEFAULT_APPLY_DELAY_MS = 1000;
|
|
33
|
+
/** Default sample count in human digest (#3125). */
|
|
34
|
+
export const DEFAULT_DIGEST_SAMPLE_LIMIT = 15;
|
|
24
35
|
const VALID_ACTIONS = new Set(["defer", "archive", "escalate", "accept"]);
|
|
25
36
|
/**
|
|
26
37
|
* Repo-qualified xBRIEF github-issue keys (`owner/name\\0number`).
|
|
@@ -308,10 +319,72 @@ function loadLatestDecisionMap(projectRoot) {
|
|
|
308
319
|
function decisionMapHas(map, repo, issueNumber) {
|
|
309
320
|
return map.has(`${repo}\0${issueNumber}`);
|
|
310
321
|
}
|
|
322
|
+
function defaultSleepMs(ms) {
|
|
323
|
+
if (ms <= 0) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
// Sync sleep: LabelClient.apply is sync; keep mirrorLabels non-async (#3125).
|
|
327
|
+
const sab = new SharedArrayBuffer(4);
|
|
328
|
+
const ia = new Int32Array(sab);
|
|
329
|
+
Atomics.wait(ia, 0, 0, ms);
|
|
330
|
+
}
|
|
331
|
+
function normalizeIssueState(raw) {
|
|
332
|
+
if (typeof raw !== "string" || raw.trim().length === 0) {
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
return raw.trim().toLowerCase();
|
|
336
|
+
}
|
|
337
|
+
function isClosedState(state) {
|
|
338
|
+
return state === "closed";
|
|
339
|
+
}
|
|
340
|
+
/** Build digest aggregates + samples from mirror items (#3125). */
|
|
341
|
+
export function buildLabelMirrorDigest(items, sampleLimit = DEFAULT_DIGEST_SAMPLE_LIMIT) {
|
|
342
|
+
const limit = Number.isFinite(sampleLimit) && sampleLimit >= 0
|
|
343
|
+
? Math.floor(sampleLimit)
|
|
344
|
+
: DEFAULT_DIGEST_SAMPLE_LIMIT;
|
|
345
|
+
const byState = {};
|
|
346
|
+
const byRule = {};
|
|
347
|
+
const byAction = {};
|
|
348
|
+
const writeItems = items.filter((i) => i.status === "planned" || i.status === "applied");
|
|
349
|
+
for (const item of writeItems) {
|
|
350
|
+
const st = item.state ?? "unknown";
|
|
351
|
+
byState[st] = (byState[st] ?? 0) + 1;
|
|
352
|
+
const rule = item.ruleKind ?? "(none)";
|
|
353
|
+
byRule[rule] = (byRule[rule] ?? 0) + 1;
|
|
354
|
+
const action = item.action ?? "(none)";
|
|
355
|
+
byAction[action] = (byAction[action] ?? 0) + 1;
|
|
356
|
+
}
|
|
357
|
+
const samples = writeItems.slice(0, limit);
|
|
358
|
+
return {
|
|
359
|
+
by_state: byState,
|
|
360
|
+
by_rule: byRule,
|
|
361
|
+
by_action: byAction,
|
|
362
|
+
samples,
|
|
363
|
+
sample_limit: limit,
|
|
364
|
+
sample_truncated: writeItems.length > limit,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
function formatMissingLabelHint(message, labels) {
|
|
368
|
+
const lower = message.toLowerCase();
|
|
369
|
+
const looksMissing = lower.includes("not found") ||
|
|
370
|
+
lower.includes("could not add label") ||
|
|
371
|
+
lower.includes("invalid label") ||
|
|
372
|
+
lower.includes("unknown label") ||
|
|
373
|
+
(lower.includes("label") && (lower.includes("404") || lower.includes("does not exist")));
|
|
374
|
+
if (!looksMissing) {
|
|
375
|
+
return message;
|
|
376
|
+
}
|
|
377
|
+
const want = labels.length > 0 ? labels.join(", ") : "triaged";
|
|
378
|
+
return (`${message} — ensure label(s) exist on the repo before --apply ` +
|
|
379
|
+
`(create missing labels e.g. \`gh label create "${want.split(",")[0]?.trim() ?? "triaged"}"\`; ` +
|
|
380
|
+
`idempotency + actionLabels must exist or apply fails closed per issue).`);
|
|
381
|
+
}
|
|
311
382
|
/**
|
|
312
|
-
* Run Tier-1 label mirror over the github-issue cache.
|
|
383
|
+
* Run Tier-1 label mirror over the github-issue cache (bootstrap mass-triage surface).
|
|
313
384
|
* Dry-run by default (no SCM writes). Pass dryRun: false to apply.
|
|
385
|
+
* Default state filter is open-only (#3125); pass includeClosed: true for archive stamps.
|
|
314
386
|
* Requires options.engine (classify/index wrapper injects it).
|
|
387
|
+
* Never calls triage:accept / never writes proposed/ xBRIEFs.
|
|
315
388
|
*/
|
|
316
389
|
export function mirrorLabels(projectRoot, options) {
|
|
317
390
|
const root = resolve(projectRoot);
|
|
@@ -321,12 +394,39 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
321
394
|
const useLiveLabels = options.useLiveLabels ?? !dryRun;
|
|
322
395
|
const client = options.client ?? (useLiveLabels || !dryRun ? new ScmLabelClient() : undefined);
|
|
323
396
|
const engine = options.engine;
|
|
397
|
+
const includeClosed = options.includeClosed === true;
|
|
398
|
+
const authorFilter = options.authorFilter !== undefined && options.authorFilter !== null
|
|
399
|
+
? options.authorFilter
|
|
400
|
+
: null;
|
|
401
|
+
const sampleLimit = options.sampleLimit ?? DEFAULT_DIGEST_SAMPLE_LIMIT;
|
|
402
|
+
const batchSize = options.batchSize !== undefined
|
|
403
|
+
? Math.max(1, Math.floor(options.batchSize))
|
|
404
|
+
: DEFAULT_APPLY_BATCH_SIZE;
|
|
405
|
+
const delayMs = options.delayMs !== undefined && options.delayMs >= 0
|
|
406
|
+
? Math.floor(options.delayMs)
|
|
407
|
+
: dryRun
|
|
408
|
+
? 0
|
|
409
|
+
: DEFAULT_APPLY_DELAY_MS;
|
|
410
|
+
const sleepMs = options.sleepMs ?? defaultSleepMs;
|
|
411
|
+
const repoFilter = options.repo !== undefined && options.repo !== null && options.repo.trim().length > 0
|
|
412
|
+
? options.repo.trim()
|
|
413
|
+
: null;
|
|
414
|
+
const filters = {
|
|
415
|
+
include_closed: includeClosed,
|
|
416
|
+
repo: repoFilter,
|
|
417
|
+
author: authorFilter !== null ? authorFilter.display : null,
|
|
418
|
+
author_logins: authorFilter !== null ? authorFilter.allowLogins : null,
|
|
419
|
+
};
|
|
324
420
|
const items = [];
|
|
325
421
|
const outcomeBase = {
|
|
326
422
|
project_root: root,
|
|
327
423
|
dry_run: dryRun,
|
|
328
424
|
policy,
|
|
425
|
+
filters,
|
|
426
|
+
batch_size: dryRun ? undefined : batchSize,
|
|
427
|
+
delay_ms: dryRun ? undefined : delayMs,
|
|
329
428
|
};
|
|
429
|
+
const emptyDigest = buildLabelMirrorDigest([], sampleLimit);
|
|
330
430
|
if (!policy.enabled) {
|
|
331
431
|
return [
|
|
332
432
|
0,
|
|
@@ -339,11 +439,15 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
339
439
|
skipped_already_triaged: 0,
|
|
340
440
|
skipped_no_match: 0,
|
|
341
441
|
skipped_unreadable: 0,
|
|
442
|
+
skipped_closed: 0,
|
|
443
|
+
skipped_author: 0,
|
|
342
444
|
errors: 0,
|
|
445
|
+
digest: emptyDigest,
|
|
343
446
|
items: [
|
|
344
447
|
{
|
|
345
448
|
repo: "",
|
|
346
449
|
issue_number: 0,
|
|
450
|
+
state: null,
|
|
347
451
|
action: null,
|
|
348
452
|
reason: null,
|
|
349
453
|
ruleKind: null,
|
|
@@ -365,8 +469,8 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
365
469
|
const decisions = loadLatestDecisionMap(root);
|
|
366
470
|
const now = options.now ?? new Date();
|
|
367
471
|
let pairs = iterCachedIssues(cacheRoot);
|
|
368
|
-
if (
|
|
369
|
-
const want =
|
|
472
|
+
if (repoFilter !== null) {
|
|
473
|
+
const want = repoFilter.toLowerCase();
|
|
370
474
|
pairs = pairs.filter(([repo]) => repo.toLowerCase() === want);
|
|
371
475
|
}
|
|
372
476
|
let planned = 0;
|
|
@@ -375,7 +479,10 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
375
479
|
let skippedAlready = 0;
|
|
376
480
|
let skippedNoMatch = 0;
|
|
377
481
|
let skippedUnreadable = 0;
|
|
482
|
+
let skippedClosed = 0;
|
|
483
|
+
let skippedAuthor = 0;
|
|
378
484
|
let errors = 0;
|
|
485
|
+
let applyWritesSinceSleep = 0;
|
|
379
486
|
for (const [repo, issueNumber] of pairs) {
|
|
380
487
|
const issue = readCachedRawIssue(cacheRoot, repo, issueNumber);
|
|
381
488
|
if (issue === null) {
|
|
@@ -383,6 +490,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
383
490
|
items.push({
|
|
384
491
|
repo,
|
|
385
492
|
issue_number: issueNumber,
|
|
493
|
+
state: null,
|
|
386
494
|
action: null,
|
|
387
495
|
reason: null,
|
|
388
496
|
ruleKind: null,
|
|
@@ -394,6 +502,48 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
394
502
|
});
|
|
395
503
|
continue;
|
|
396
504
|
}
|
|
505
|
+
const state = normalizeIssueState(issue.state);
|
|
506
|
+
// Open-only default: skip closed before classify (avoids mass-stamping archive).
|
|
507
|
+
if (!includeClosed && isClosedState(state)) {
|
|
508
|
+
skippedClosed += 1;
|
|
509
|
+
items.push({
|
|
510
|
+
repo,
|
|
511
|
+
issue_number: issueNumber,
|
|
512
|
+
state,
|
|
513
|
+
action: null,
|
|
514
|
+
reason: null,
|
|
515
|
+
ruleKind: null,
|
|
516
|
+
current: issueLabelNames(issue).sort(),
|
|
517
|
+
desired: [],
|
|
518
|
+
add: [],
|
|
519
|
+
status: "skipped_closed",
|
|
520
|
+
message: "open-only default; pass includeClosed / --include-closed to mirror closed issues",
|
|
521
|
+
});
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
// Author filter (#3129): AND with open-only / other filters; missing author = non-match.
|
|
525
|
+
if (authorFilter !== null) {
|
|
526
|
+
const login = authorLoginFromRawIssue(issue);
|
|
527
|
+
if (!matchesAuthorFilter(login, authorFilter)) {
|
|
528
|
+
skippedAuthor += 1;
|
|
529
|
+
items.push({
|
|
530
|
+
repo,
|
|
531
|
+
issue_number: issueNumber,
|
|
532
|
+
state,
|
|
533
|
+
action: null,
|
|
534
|
+
reason: null,
|
|
535
|
+
ruleKind: null,
|
|
536
|
+
current: issueLabelNames(issue).sort(),
|
|
537
|
+
desired: [],
|
|
538
|
+
add: [],
|
|
539
|
+
status: "skipped_author",
|
|
540
|
+
message: login === null
|
|
541
|
+
? `author filter ${authorFilter.display}: missing author on cache row (unknown — excluded)`
|
|
542
|
+
: `author filter ${authorFilter.display}: author.login=${login} does not match`,
|
|
543
|
+
});
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
397
547
|
let current;
|
|
398
548
|
if (useLiveLabels && client !== undefined) {
|
|
399
549
|
try {
|
|
@@ -406,6 +556,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
406
556
|
items.push({
|
|
407
557
|
repo,
|
|
408
558
|
issue_number: issueNumber,
|
|
559
|
+
state,
|
|
409
560
|
action: null,
|
|
410
561
|
reason: null,
|
|
411
562
|
ruleKind: null,
|
|
@@ -427,6 +578,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
427
578
|
items.push({
|
|
428
579
|
repo,
|
|
429
580
|
issue_number: issueNumber,
|
|
581
|
+
state,
|
|
430
582
|
action: null,
|
|
431
583
|
reason: null,
|
|
432
584
|
ruleKind: null,
|
|
@@ -455,6 +607,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
455
607
|
items.push({
|
|
456
608
|
repo,
|
|
457
609
|
issue_number: issueNumber,
|
|
610
|
+
state,
|
|
458
611
|
action: null,
|
|
459
612
|
reason: null,
|
|
460
613
|
ruleKind: null,
|
|
@@ -473,6 +626,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
473
626
|
items.push({
|
|
474
627
|
repo,
|
|
475
628
|
issue_number: issueNumber,
|
|
629
|
+
state,
|
|
476
630
|
action: classification.action,
|
|
477
631
|
reason: classification.reason,
|
|
478
632
|
ruleKind: classification.ruleKind,
|
|
@@ -488,6 +642,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
488
642
|
items.push({
|
|
489
643
|
repo,
|
|
490
644
|
issue_number: issueNumber,
|
|
645
|
+
state,
|
|
491
646
|
action: classification.action,
|
|
492
647
|
reason: classification.reason,
|
|
493
648
|
ruleKind: classification.ruleKind,
|
|
@@ -498,7 +653,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
498
653
|
});
|
|
499
654
|
continue;
|
|
500
655
|
}
|
|
501
|
-
// --apply path: SCM boundary + write
|
|
656
|
+
// --apply path: SCM boundary + write (batched + delay for rate-limit awareness)
|
|
502
657
|
const mutateGate = isRepoMutationAllowed(repo, root, {
|
|
503
658
|
allowCrossRepo: options.allowCrossRepo,
|
|
504
659
|
allowlist: options.repoAllowlist,
|
|
@@ -509,6 +664,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
509
664
|
items.push({
|
|
510
665
|
repo,
|
|
511
666
|
issue_number: issueNumber,
|
|
667
|
+
state,
|
|
512
668
|
action: classification.action,
|
|
513
669
|
reason: classification.reason,
|
|
514
670
|
ruleKind: classification.ruleKind,
|
|
@@ -525,6 +681,7 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
525
681
|
items.push({
|
|
526
682
|
repo,
|
|
527
683
|
issue_number: issueNumber,
|
|
684
|
+
state,
|
|
528
685
|
action: classification.action,
|
|
529
686
|
reason: classification.reason,
|
|
530
687
|
ruleKind: classification.ruleKind,
|
|
@@ -537,11 +694,18 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
537
694
|
continue;
|
|
538
695
|
}
|
|
539
696
|
try {
|
|
697
|
+
// Count every SCM write *attempt* toward the batch (including failures) so
|
|
698
|
+
// rate-limit delay still applies under partial failure storms (#3125 Greptile P1).
|
|
699
|
+
if (applyWritesSinceSleep > 0 && applyWritesSinceSleep % batchSize === 0 && delayMs > 0) {
|
|
700
|
+
sleepMs(delayMs);
|
|
701
|
+
}
|
|
702
|
+
applyWritesSinceSleep += 1;
|
|
540
703
|
client.apply(repo, issueNumber, add, []);
|
|
541
704
|
applied += 1;
|
|
542
705
|
items.push({
|
|
543
706
|
repo,
|
|
544
707
|
issue_number: issueNumber,
|
|
708
|
+
state,
|
|
545
709
|
action: classification.action,
|
|
546
710
|
reason: classification.reason,
|
|
547
711
|
ruleKind: classification.ruleKind,
|
|
@@ -553,9 +717,11 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
553
717
|
}
|
|
554
718
|
catch (exc) {
|
|
555
719
|
errors += 1;
|
|
720
|
+
const rawMsg = exc instanceof Error ? exc.message : String(exc);
|
|
556
721
|
items.push({
|
|
557
722
|
repo,
|
|
558
723
|
issue_number: issueNumber,
|
|
724
|
+
state,
|
|
559
725
|
action: classification.action,
|
|
560
726
|
reason: classification.reason,
|
|
561
727
|
ruleKind: classification.ruleKind,
|
|
@@ -563,10 +729,12 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
563
729
|
desired,
|
|
564
730
|
add,
|
|
565
731
|
status: "error",
|
|
566
|
-
message:
|
|
732
|
+
message: formatMissingLabelHint(rawMsg, add),
|
|
567
733
|
});
|
|
734
|
+
// Partial failure: continue remaining issues (idempotent re-run skips applied).
|
|
568
735
|
}
|
|
569
736
|
}
|
|
737
|
+
const digest = buildLabelMirrorDigest(items, sampleLimit);
|
|
570
738
|
const outcome = {
|
|
571
739
|
...outcomeBase,
|
|
572
740
|
scanned: pairs.length,
|
|
@@ -576,35 +744,75 @@ export function mirrorLabels(projectRoot, options) {
|
|
|
576
744
|
skipped_already_triaged: skippedAlready,
|
|
577
745
|
skipped_no_match: skippedNoMatch,
|
|
578
746
|
skipped_unreadable: skippedUnreadable,
|
|
747
|
+
skipped_closed: skippedClosed,
|
|
748
|
+
skipped_author: skippedAuthor,
|
|
579
749
|
errors,
|
|
750
|
+
digest,
|
|
580
751
|
items,
|
|
581
752
|
};
|
|
582
753
|
return [errors > 0 ? 1 : 0, outcome];
|
|
583
754
|
}
|
|
584
|
-
|
|
755
|
+
function formatCountMap(map) {
|
|
756
|
+
const keys = Object.keys(map).sort();
|
|
757
|
+
if (keys.length === 0) {
|
|
758
|
+
return [" (none)"];
|
|
759
|
+
}
|
|
760
|
+
return keys.map((k) => ` ${k}: ${map[k]}`);
|
|
761
|
+
}
|
|
762
|
+
/** Human-readable digest for dry-run / apply reports (bootstrap mass-triage UX). */
|
|
585
763
|
export function renderLabelMirrorReport(outcome) {
|
|
586
764
|
const lines = [];
|
|
587
765
|
const mode = outcome.dry_run ? "dry-run" : "apply";
|
|
588
|
-
lines.push(`triage:classify --mirror (${mode})`);
|
|
766
|
+
lines.push(`triage:classify --mirror (${mode}) — bootstrap mass-triage (#1423 Wave 2)`);
|
|
767
|
+
const stateFilter = outcome.filters.include_closed ? "all (include-closed)" : "open-only";
|
|
768
|
+
const repoPart = outcome.filters.repo ?? "*";
|
|
769
|
+
const authorPart = outcome.filters.author ?? "*";
|
|
770
|
+
lines.push(`filters: state=${stateFilter} repo=${repoPart} author=${authorPart}`);
|
|
589
771
|
lines.push(`scanned=${outcome.scanned} planned=${outcome.planned} applied=${outcome.applied} ` +
|
|
590
772
|
`unchanged=${outcome.unchanged} already_triaged=${outcome.skipped_already_triaged} ` +
|
|
591
|
-
`no_match=${outcome.skipped_no_match}
|
|
592
|
-
`
|
|
773
|
+
`no_match=${outcome.skipped_no_match} closed_skipped=${outcome.skipped_closed} ` +
|
|
774
|
+
`author_skipped=${outcome.skipped_author} ` +
|
|
775
|
+
`unreadable=${outcome.skipped_unreadable} errors=${outcome.errors}`);
|
|
593
776
|
lines.push(`idempotencyLabel=${outcome.policy.idempotencyLabel} alwaysLabels=${JSON.stringify(outcome.policy.alwaysLabels)}`);
|
|
777
|
+
if (!outcome.dry_run) {
|
|
778
|
+
lines.push(`apply: batch_size=${outcome.batch_size ?? DEFAULT_APPLY_BATCH_SIZE} delay_ms=${outcome.delay_ms ?? DEFAULT_APPLY_DELAY_MS}`);
|
|
779
|
+
}
|
|
594
780
|
lines.push("");
|
|
595
|
-
|
|
596
|
-
lines.push(outcome.
|
|
597
|
-
|
|
781
|
+
lines.push("By state (planned/applied):");
|
|
782
|
+
lines.push(...formatCountMap(outcome.digest.by_state));
|
|
783
|
+
lines.push("By rule (planned/applied):");
|
|
784
|
+
lines.push(...formatCountMap(outcome.digest.by_rule));
|
|
785
|
+
lines.push("By action (planned/applied):");
|
|
786
|
+
lines.push(...formatCountMap(outcome.digest.by_action));
|
|
787
|
+
lines.push("");
|
|
788
|
+
const writeTotal = outcome.planned + outcome.applied;
|
|
789
|
+
lines.push(outcome.dry_run
|
|
790
|
+
? `Samples (up to ${outcome.digest.sample_limit} of ${writeTotal} planned):`
|
|
791
|
+
: `Samples (up to ${outcome.digest.sample_limit} of ${writeTotal} applied/planned):`);
|
|
792
|
+
if (outcome.digest.samples.length === 0) {
|
|
598
793
|
lines.push("- none");
|
|
599
794
|
}
|
|
600
795
|
else {
|
|
601
|
-
for (const item of
|
|
796
|
+
for (const item of outcome.digest.samples) {
|
|
602
797
|
const actionPart = item.action !== null ? ` action=${item.action}` : "";
|
|
603
798
|
const rulePart = item.ruleKind !== null ? ` rule=${item.ruleKind}` : "";
|
|
799
|
+
const statePart = item.state !== null ? ` state=${item.state}` : "";
|
|
604
800
|
const addPart = sanitizeReportFragment(item.add.join(", +"));
|
|
605
|
-
lines.push(`- ${item.repo}#${item.issue_number}:${actionPart}${rulePart} +${addPart}`);
|
|
801
|
+
lines.push(`- ${item.repo}#${item.issue_number}:${statePart}${actionPart}${rulePart} +${addPart}`);
|
|
802
|
+
}
|
|
803
|
+
if (outcome.digest.sample_truncated) {
|
|
804
|
+
const remaining = writeTotal - outcome.digest.samples.length;
|
|
805
|
+
lines.push(`… and ${remaining} more (use --json for full items list)`);
|
|
606
806
|
}
|
|
607
807
|
}
|
|
808
|
+
if (outcome.skipped_closed > 0) {
|
|
809
|
+
lines.push("");
|
|
810
|
+
lines.push(`Skipped closed (open-only default): ${outcome.skipped_closed} — re-run with --include-closed to include archive`);
|
|
811
|
+
}
|
|
812
|
+
if (outcome.skipped_author > 0) {
|
|
813
|
+
lines.push("");
|
|
814
|
+
lines.push(`Skipped (author filter ${outcome.filters.author ?? "?"}): ${outcome.skipped_author}`);
|
|
815
|
+
}
|
|
608
816
|
const already = outcome.items.filter((i) => i.status === "skipped_already_triaged");
|
|
609
817
|
if (already.length > 0) {
|
|
610
818
|
lines.push("");
|
|
@@ -617,19 +825,19 @@ export function renderLabelMirrorReport(outcome) {
|
|
|
617
825
|
const errs = outcome.items.filter((i) => i.status === "error");
|
|
618
826
|
if (errs.length > 0) {
|
|
619
827
|
lines.push("");
|
|
620
|
-
lines.push(
|
|
828
|
+
lines.push(`Errors (partial failure report; ${errs.length} of ${outcome.scanned}):`);
|
|
621
829
|
for (const item of errs) {
|
|
622
830
|
const msg = sanitizeReportFragment(item.message ?? "unknown error");
|
|
623
831
|
lines.push(`- ${item.repo}#${item.issue_number}: ${msg}`);
|
|
624
832
|
}
|
|
625
833
|
}
|
|
626
|
-
if (outcome.dry_run &&
|
|
834
|
+
if (outcome.dry_run && writeTotal > 0) {
|
|
627
835
|
lines.push("");
|
|
628
|
-
lines.push("Dry-run
|
|
836
|
+
lines.push("Dry-run — re-run with --mirror --apply to write these labels via SCM (batched; never triage:accept).");
|
|
629
837
|
}
|
|
630
838
|
return `${lines.join("\n")}\n`;
|
|
631
839
|
}
|
|
632
|
-
/** JSON-serializable outcome
|
|
840
|
+
/** JSON-serializable outcome including Wave 2 digest aggregates. */
|
|
633
841
|
export function labelMirrorOutcomeToJson(outcome) {
|
|
634
842
|
return {
|
|
635
843
|
project_root: outcome.project_root,
|
|
@@ -641,25 +849,47 @@ export function labelMirrorOutcomeToJson(outcome) {
|
|
|
641
849
|
skipped_already_triaged: outcome.skipped_already_triaged,
|
|
642
850
|
skipped_no_match: outcome.skipped_no_match,
|
|
643
851
|
skipped_unreadable: outcome.skipped_unreadable,
|
|
852
|
+
skipped_closed: outcome.skipped_closed,
|
|
853
|
+
skipped_author: outcome.skipped_author,
|
|
644
854
|
errors: outcome.errors,
|
|
855
|
+
filters: {
|
|
856
|
+
include_closed: outcome.filters.include_closed,
|
|
857
|
+
repo: outcome.filters.repo,
|
|
858
|
+
author: outcome.filters.author,
|
|
859
|
+
author_logins: outcome.filters.author_logins,
|
|
860
|
+
},
|
|
861
|
+
digest: {
|
|
862
|
+
by_state: { ...outcome.digest.by_state },
|
|
863
|
+
by_rule: { ...outcome.digest.by_rule },
|
|
864
|
+
by_action: { ...outcome.digest.by_action },
|
|
865
|
+
sample_limit: outcome.digest.sample_limit,
|
|
866
|
+
sample_truncated: outcome.digest.sample_truncated,
|
|
867
|
+
samples: outcome.digest.samples.map((i) => itemToJson(i)),
|
|
868
|
+
},
|
|
869
|
+
...(outcome.batch_size !== undefined ? { batch_size: outcome.batch_size } : {}),
|
|
870
|
+
...(outcome.delay_ms !== undefined ? { delay_ms: outcome.delay_ms } : {}),
|
|
645
871
|
policy: {
|
|
646
872
|
enabled: outcome.policy.enabled,
|
|
647
873
|
idempotencyLabel: outcome.policy.idempotencyLabel,
|
|
648
874
|
alwaysLabels: [...outcome.policy.alwaysLabels],
|
|
649
875
|
actionLabels: Object.fromEntries(Object.entries(outcome.policy.actionLabels).map(([k, v]) => [k, [...(v ?? [])]])),
|
|
650
876
|
},
|
|
651
|
-
items: outcome.items.map((i) => (
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
877
|
+
items: outcome.items.map((i) => itemToJson(i)),
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
function itemToJson(i) {
|
|
881
|
+
return {
|
|
882
|
+
repo: i.repo,
|
|
883
|
+
issue_number: i.issue_number,
|
|
884
|
+
state: i.state,
|
|
885
|
+
action: i.action,
|
|
886
|
+
reason: i.reason,
|
|
887
|
+
ruleKind: i.ruleKind,
|
|
888
|
+
current: [...i.current],
|
|
889
|
+
desired: [...i.desired],
|
|
890
|
+
add: [...i.add],
|
|
891
|
+
status: i.status,
|
|
892
|
+
...(i.message !== undefined ? { message: i.message } : {}),
|
|
663
893
|
};
|
|
664
894
|
}
|
|
665
895
|
/** Validate triageLabelMirror on a plan object (vbrief_validate hook). */
|
|
@@ -114,12 +114,12 @@ export declare const registryData: {
|
|
|
114
114
|
readonly "task triage:queue": {
|
|
115
115
|
readonly name: "task triage:queue";
|
|
116
116
|
readonly summary: "Ranked candidate list";
|
|
117
|
-
readonly refs: "(D11 / #1128)";
|
|
118
|
-
readonly description: "Print the ranked triage queue from the local cache. Groups (display order): [ORPHAN] -> [RESUME] -> [URGENT] -> untriaged -> other -> [BLOCKED]. Within-group default = updated_at desc; consumer plan.policy.triageRankingLabels[] re-orders within-group by matched-label declared order. Items whose linked vBRIEF is blocked (status:blocked / unresolved depends_on) are demoted into [BLOCKED] unless --include-blocked is passed (#1286).";
|
|
119
|
-
readonly usage: "task triage:queue [-- --limit=N] [--include-blocked] [--repo=owner/name]";
|
|
120
|
-
readonly flags: readonly [readonly ["--limit N", "10", "Max rows to print."], readonly ["--include-blocked", "(off)", "Re-surface blocked items into their natural group (#1286)."], readonly ["--repo owner/name", "(git remote)", "Explicit repo override."]];
|
|
121
|
-
readonly examples: readonly ["task triage:queue", "task triage:queue -- --limit=20
|
|
122
|
-
readonly see_also: readonly ["task triage:show", "task triage:audit", "#1119 / D11"];
|
|
117
|
+
readonly refs: "(D11 / #1128, #3129 / #1318 Layer 1)";
|
|
118
|
+
readonly description: "Print the ranked triage queue from the local cache. Groups (display order): [ORPHAN] -> [RESUME] -> [URGENT] -> untriaged -> other -> [BLOCKED]. Within-group default = updated_at desc; consumer plan.policy.triageRankingLabels[] re-orders within-group by matched-label declared order. Items whose linked vBRIEF is blocked (status:blocked / unresolved depends_on) are demoted into [BLOCKED] unless --include-blocked is passed (#1286). Optional --author LOGIN filters to cache author.login (exact; @me resolves to authenticated login; comma allow-list; missing author counted as unknown and disclosed in the header) (#3129 / #1318 Layer 1).";
|
|
119
|
+
readonly usage: "task triage:queue [-- --limit=N] [--include-blocked] [--repo=owner/name] [--author LOGIN|@me] [--author-mine]";
|
|
120
|
+
readonly flags: readonly [readonly ["--limit N", "10", "Max rows to print."], readonly ["--include-blocked", "(off)", "Re-surface blocked items into their natural group (#1286)."], readonly ["--repo owner/name", "(git remote)", "Explicit repo override."], readonly ["--author LOGIN|@me", "(none)", "Only issues whose cache author.login matches (exact; @me = gh user; comma allow-list) (#3129)."], readonly ["--author-mine", "(off)", "Alias for --author @me (#1318 / #3129)."]];
|
|
121
|
+
readonly examples: readonly ["task triage:queue", "task triage:queue -- --limit=20", "task triage:queue -- --author @me", "task triage:queue -- --author alice,bob --limit=20"];
|
|
122
|
+
readonly see_also: readonly ["task triage:show", "task triage:audit", "task triage:classify", "#1119 / D11", "#3129"];
|
|
123
123
|
readonly placeholder: false;
|
|
124
124
|
};
|
|
125
125
|
readonly "task triage:audit": {
|
|
@@ -168,13 +168,13 @@ export declare const registryData: {
|
|
|
168
168
|
};
|
|
169
169
|
readonly "task triage:classify": {
|
|
170
170
|
readonly name: "task triage:classify";
|
|
171
|
-
readonly summary: "Inspect / validate auto-classification
|
|
172
|
-
readonly refs: "(D10 / #1129, #1423 Wave 1)";
|
|
173
|
-
readonly description: "Inspect or validate the auto-classification rule set. --list renders effective rules (framework universal first, consumer overrides next). --validate exits non-zero on a malformed plan.policy.triageAutoClassify or triageLabelMirror. --mirror
|
|
174
|
-
readonly usage: "task triage:classify -- [--list | --validate | --mirror [--apply] [--repo owner/name] [--json] [--allow-cross-repo]]";
|
|
175
|
-
readonly flags: readonly [readonly ["--list", "(default)", "Print effective rules + hold markers."], readonly ["--validate", "(off)", "Validate plan.policy.triageAutoClassify + triageLabelMirror."], readonly ["--mirror", "(off)", "
|
|
176
|
-
readonly examples: readonly ["task triage:classify -- --list", "task triage:classify -- --validate", "task triage:classify -- --mirror", "task triage:classify -- --mirror --apply --repo owner/name"];
|
|
177
|
-
readonly see_also: readonly ["task triage:bootstrap", "task triage:queue", "task vbrief:reconcile:labels", "#1119 / D10", "#1423"];
|
|
171
|
+
readonly summary: "Inspect / validate auto-classification; bootstrap mass-triage label mirror";
|
|
172
|
+
readonly refs: "(D10 / #1129, #1423 Wave 1–2 / #3125, #3129)";
|
|
173
|
+
readonly description: "Inspect or validate the auto-classification rule set. --list renders effective rules (framework universal first, consumer overrides next). --validate exits non-zero on a malformed plan.policy.triageAutoClassify or triageLabelMirror. --mirror is the bootstrap mass-triage entrypoint (#3125): classifies the github-issue cache and mirrors outcomes as SCM labels. Open-only by default (opt-in --include-closed); optional --author LOGIN scopes plan/apply to matching author.login (AND with open-only; #3129); dry-run digest shows totals + by state/rule/action + samples and surfaces the author filter; --apply batches writes with rate-limit delay. Never calls triage:accept / never writes proposed/ xBRIEFs.";
|
|
174
|
+
readonly usage: "task triage:classify -- [--list | --validate | --mirror [--apply] [--include-closed] [--author LOGIN|@me] [--repo owner/name] [--batch-size N] [--delay-ms N] [--sample-limit N] [--json] [--allow-cross-repo]]";
|
|
175
|
+
readonly flags: readonly [readonly ["--list", "(default)", "Print effective rules + hold markers."], readonly ["--validate", "(off)", "Validate plan.policy.triageAutoClassify + triageLabelMirror."], readonly ["--mirror", "(off)", "Bootstrap mass-triage label mirror: classify cache → planned/applied labels (dry-run default, open-only)."], readonly ["--apply", "(off)", "With --mirror: write labels via SCM (batched; requires github SCM boundary)."], readonly ["--include-closed", "(off)", "With --mirror: include closed issues (default open-only avoids archive mass-stamp)."], readonly ["--author LOGIN|@me", "(none)", "With --mirror: only plan/apply issues whose cache author.login matches (exact; @me; comma allow-list) (#3129)."], readonly ["--author-mine", "(off)", "With --mirror: alias for --author @me (#3129)."], readonly ["--repo owner/name", "(all cached)", "Limit mirror to one repo."], readonly ["--batch-size N", "10", "With --mirror --apply: writes per batch before delay."], readonly ["--delay-ms N", "1000", "With --mirror --apply: ms sleep between batches (rate-limit)."], readonly ["--sample-limit N", "15", "With --mirror: max samples in human digest."], readonly ["--json", "(off)", "With --mirror: structured JSON outcome including digest aggregates."], readonly ["--allow-cross-repo", "(off)", "With --mirror --apply: allow non-project repos (#2601)."]];
|
|
176
|
+
readonly examples: readonly ["task triage:classify -- --list", "task triage:classify -- --validate", "task triage:classify -- --mirror", "task triage:classify -- --mirror --author @me --repo owner/name", "task triage:classify -- --mirror --repo owner/name --json", "task triage:classify -- --mirror --apply --repo owner/name --batch-size 10 --delay-ms 1000", "task triage:classify -- --mirror --include-closed --repo owner/name"];
|
|
177
|
+
readonly see_also: readonly ["task triage:bootstrap", "task triage:queue", "task vbrief:reconcile:labels", "#1119 / D10", "#1423", "#3125", "#3129"];
|
|
178
178
|
readonly placeholder: false;
|
|
179
179
|
};
|
|
180
180
|
readonly "task triage:bootstrap": {
|
|
@@ -298,37 +298,48 @@ export declare const registryData: {
|
|
|
298
298
|
readonly see_also: readonly ["task triage:subscribe", "task triage:scope", "#1119 / D14"];
|
|
299
299
|
readonly placeholder: false;
|
|
300
300
|
};
|
|
301
|
-
readonly "task triage:
|
|
302
|
-
readonly name: "task triage:
|
|
303
|
-
readonly summary: "
|
|
304
|
-
readonly refs: "(
|
|
305
|
-
readonly description: "Move closed-
|
|
306
|
-
readonly usage: "task triage:
|
|
307
|
-
readonly flags: readonly [readonly ["--dry-run", "(off)", "
|
|
308
|
-
readonly examples: readonly ["task triage:
|
|
309
|
-
readonly see_also: readonly ["task triage:archive-list", "task triage:restore-from-archive", "
|
|
310
|
-
readonly placeholder:
|
|
301
|
+
readonly "task triage:cache-archive": {
|
|
302
|
+
readonly name: "task triage:cache-archive";
|
|
303
|
+
readonly summary: "Reversible archive of closed github-issue cache entries";
|
|
304
|
+
readonly refs: "(#1137)";
|
|
305
|
+
readonly description: "Move closed-and-aged live `.deft-cache/github-issue/` entries under `.deft-cache/archived/github-issue/...` with archive-meta.json. Operator-only; never auto on check/session/sync. Distinct from task cache:prune (TTL hard-delete). Skips issues referenced in xbrief/{proposed,pending,active}. Alias: cache:archive-closed.";
|
|
306
|
+
readonly usage: "task triage:cache-archive -- [--dry-run] [--older-than-days 30] [--repo owner/name] [--json] [--terminal-decision-only]";
|
|
307
|
+
readonly flags: readonly [readonly ["--dry-run", "(off)", "Report eligible entries without moving."], readonly ["--older-than-days N", "30", "Minimum age of closed_at (or fetched_at/mtime fallback)."], readonly ["--repo owner/name", "(all)", "Limit to one repo."], readonly ["--json", "(off)", "Structured summary."], readonly ["--terminal-decision-only", "(off)", "Only archive when latest candidates decision is reject or mark-duplicate."]];
|
|
308
|
+
readonly examples: readonly ["task triage:cache-archive -- --dry-run", "task triage:cache-archive -- --older-than-days 30 --repo deftai/directive"];
|
|
309
|
+
readonly see_also: readonly ["task triage:archive-list", "task triage:restore-from-archive", "task cache:prune", "#1137"];
|
|
310
|
+
readonly placeholder: false;
|
|
311
311
|
};
|
|
312
312
|
readonly "task triage:archive-list": {
|
|
313
313
|
readonly name: "task triage:archive-list";
|
|
314
|
-
readonly summary: "List archived entries";
|
|
315
|
-
readonly refs: "(
|
|
316
|
-
readonly description: "
|
|
317
|
-
readonly usage: "task triage:archive-list [-- --
|
|
318
|
-
readonly flags: readonly [readonly ["--
|
|
319
|
-
readonly examples: readonly ["task triage:archive-list"];
|
|
320
|
-
readonly see_also: readonly ["task triage:
|
|
321
|
-
readonly placeholder:
|
|
314
|
+
readonly summary: "List archived github-issue cache entries";
|
|
315
|
+
readonly refs: "(#1137)";
|
|
316
|
+
readonly description: "List `.deft-cache/archived/github-issue/...` entries newest archived_at first. Alias: cache:archive-list.";
|
|
317
|
+
readonly usage: "task triage:archive-list -- [--repo owner/name] [--format=json] [--since ISO] [--limit N]";
|
|
318
|
+
readonly flags: readonly [readonly ["--repo owner/name", "(all)", "Limit to one repo."], readonly ["--format=json", "text", "JSON listing."], readonly ["--since ISO", "(none)", "Only entries archived at/after this timestamp."], readonly ["--limit N", "(none)", "Cap result count."]];
|
|
319
|
+
readonly examples: readonly ["task triage:archive-list -- --format=json"];
|
|
320
|
+
readonly see_also: readonly ["task triage:cache-archive", "task triage:restore-from-archive", "#1137"];
|
|
321
|
+
readonly placeholder: false;
|
|
322
322
|
};
|
|
323
323
|
readonly "task triage:restore-from-archive": {
|
|
324
324
|
readonly name: "task triage:restore-from-archive";
|
|
325
|
-
readonly summary: "Restore archived entry to live cache";
|
|
326
|
-
readonly refs: "(
|
|
327
|
-
readonly description: "Move an archived entry back to the live
|
|
328
|
-
readonly usage: "task triage:restore-from-archive --
|
|
329
|
-
readonly flags: readonly [readonly ["
|
|
330
|
-
readonly examples: readonly ["task triage:restore-from-archive --
|
|
331
|
-
readonly see_also: readonly ["task triage:archive
|
|
325
|
+
readonly summary: "Restore archived issue entry to live cache";
|
|
326
|
+
readonly refs: "(#1137)";
|
|
327
|
+
readonly description: "Move an archived github-issue entry back to the live key path. Idempotent if already live with matching content; refuse live conflict unless --force. Alias: cache:restore-from-archive.";
|
|
328
|
+
readonly usage: "task triage:restore-from-archive -- --issue N --repo owner/name [--force]";
|
|
329
|
+
readonly flags: readonly [readonly ["--issue N", "(required unless --key)", "Issue number."], readonly ["--repo owner/name", "(required with --issue)", "Upstream repo."], readonly ["--key owner/repo/N", "(alt)", "Full cache key."], readonly ["--force", "(off)", "Replace live path when content differs."]];
|
|
330
|
+
readonly examples: readonly ["task triage:restore-from-archive -- --issue 1234 --repo deftai/directive"];
|
|
331
|
+
readonly see_also: readonly ["task triage:cache-archive", "task triage:show", "#1137"];
|
|
332
|
+
readonly placeholder: false;
|
|
333
|
+
};
|
|
334
|
+
readonly "task triage:audit:prune": {
|
|
335
|
+
readonly name: "task triage:audit:prune";
|
|
336
|
+
readonly summary: "Legacy name — use triage:cache-archive";
|
|
337
|
+
readonly refs: "(#1137 supersedes D19 name)";
|
|
338
|
+
readonly description: "Historical D19 placeholder name. Implemented surface is task triage:cache-archive (reversible closed github-issue cache archive). Do not confuse with task cache:prune (TTL hard-delete).";
|
|
339
|
+
readonly usage: "task triage:cache-archive -- [--dry-run] [--older-than-days N]";
|
|
340
|
+
readonly flags: readonly [readonly ["--dry-run", "(off)", "Preview eligible entries without writing."], readonly ["--older-than-days N", "30", "Age threshold."]];
|
|
341
|
+
readonly examples: readonly ["task triage:cache-archive -- --dry-run"];
|
|
342
|
+
readonly see_also: readonly ["task triage:cache-archive", "task triage:archive-list", "#1137"];
|
|
332
343
|
readonly placeholder: true;
|
|
333
344
|
};
|
|
334
345
|
readonly "task triage:audit-log:rotate": {
|