@deftai/directive-core 0.69.0 → 0.71.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/branch/evaluate.js +7 -0
- package/dist/deposit/contain.d.ts +41 -0
- package/dist/deposit/contain.js +113 -0
- package/dist/deposit/copy-tree.js +8 -2
- package/dist/doctor/checks.d.ts +11 -0
- package/dist/doctor/checks.js +75 -2
- package/dist/doctor/doctor-state.js +2 -2
- package/dist/doctor/main.js +54 -1
- package/dist/doctor/manifest.d.ts +20 -0
- package/dist/doctor/manifest.js +22 -0
- package/dist/doctor/types.d.ts +8 -0
- package/dist/eval/crud-telemetry.d.ts +59 -0
- package/dist/eval/crud-telemetry.js +307 -0
- package/dist/eval/health.d.ts +52 -0
- package/dist/eval/health.js +240 -0
- package/dist/eval/readback.d.ts +38 -0
- package/dist/eval/readback.js +209 -0
- package/dist/eval/report.d.ts +53 -0
- package/dist/eval/report.js +161 -0
- package/dist/eval/run.d.ts +79 -0
- package/dist/eval/run.js +309 -0
- package/dist/events/attribution-constants.d.ts +13 -0
- package/dist/events/attribution-constants.js +18 -0
- package/dist/events/attribution-ledger.d.ts +43 -0
- package/dist/events/attribution-ledger.js +61 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/init-deposit/gitignore.js +5 -5
- package/dist/init-deposit/init-deposit.js +6 -0
- package/dist/init-deposit/refresh.js +5 -0
- package/dist/intake/issue-ingest.d.ts +11 -0
- package/dist/intake/issue-ingest.js +86 -11
- package/dist/layout/resolve.d.ts +2 -2
- package/dist/layout/resolve.js +2 -2
- package/dist/lifecycle/events.js +2 -0
- package/dist/policy/index.d.ts +2 -1
- package/dist/policy/index.js +15 -2
- package/dist/policy/plan-extensions.d.ts +31 -0
- package/dist/policy/plan-extensions.js +45 -0
- package/dist/policy/value-feedback.d.ts +56 -0
- package/dist/policy/value-feedback.js +284 -0
- package/dist/policy/wip.d.ts +2 -2
- package/dist/policy/wip.js +2 -2
- package/dist/preflight-cache/evaluate.js +4 -3
- package/dist/scope/audit-log.js +3 -3
- package/dist/scope/transition.js +16 -5
- package/dist/session/session-start.js +20 -0
- package/dist/slice/record.js +3 -3
- package/dist/swarm/routing.js +10 -3
- package/dist/triage/actions/candidates-log.d.ts +4 -4
- package/dist/triage/actions/candidates-log.js +4 -7
- package/dist/triage/bootstrap/gitignore.d.ts +7 -3
- package/dist/triage/bootstrap/gitignore.js +67 -37
- package/dist/triage/bootstrap/index.d.ts +1 -1
- package/dist/triage/bootstrap/index.js +4 -3
- package/dist/triage/bulk/index.d.ts +11 -2
- package/dist/triage/bulk/index.js +43 -6
- package/dist/triage/cache-path.d.ts +39 -0
- package/dist/triage/cache-path.js +98 -0
- package/dist/triage/help/registry-data.d.ts +53 -20
- package/dist/triage/help/registry-data.js +104 -20
- package/dist/triage/index.d.ts +2 -0
- package/dist/triage/index.js +2 -0
- package/dist/triage/queue/audit.js +2 -2
- package/dist/triage/queue/cache.js +2 -2
- package/dist/triage/reconcile/reconcile.js +4 -3
- package/dist/triage/scope/cli.d.ts +2 -1
- package/dist/triage/scope/cli.js +30 -6
- package/dist/triage/scope/mutations-core.js +3 -2
- package/dist/triage/scope/mutations.d.ts +10 -0
- package/dist/triage/scope/mutations.js +22 -0
- package/dist/triage/subscribe/index.d.ts +1 -1
- package/dist/triage/subscribe/index.js +4 -3
- package/dist/triage/summary/index.d.ts +2 -2
- package/dist/triage/summary/index.js +4 -3
- package/dist/triage/summary/reconcilable.d.ts +1 -1
- package/dist/triage/summary/reconcilable.js +3 -2
- package/dist/triage/welcome/constants.d.ts +3 -4
- package/dist/triage/welcome/constants.js +3 -4
- package/dist/triage/welcome/index.d.ts +1 -0
- package/dist/triage/welcome/index.js +1 -0
- package/dist/triage/welcome/onboard.d.ts +35 -0
- package/dist/triage/welcome/onboard.js +94 -0
- package/dist/triage/welcome/prior-state.js +3 -2
- package/dist/triage/welcome/summary.js +5 -4
- package/dist/umbrella-current-shape/index.d.ts +25 -1
- package/dist/umbrella-current-shape/index.js +84 -4
- package/dist/value/adoption-emit.d.ts +14 -0
- package/dist/value/adoption-emit.js +67 -0
- package/dist/value/adoption-registry.d.ts +62 -0
- package/dist/value/adoption-registry.js +214 -0
- package/dist/value/feedback-file.d.ts +67 -0
- package/dist/value/feedback-file.js +353 -0
- package/dist/value/friction-emit.d.ts +10 -0
- package/dist/value/friction-emit.js +24 -0
- package/dist/value/readback.d.ts +86 -0
- package/dist/value/readback.js +503 -0
- package/dist/vbrief-build/project-definition-io.d.ts +6 -0
- package/dist/vbrief-build/project-definition-io.js +7 -2
- package/dist/vbrief-validate/decomposition.js +1 -1
- package/dist/vbrief-validate/precutover.js +7 -3
- package/dist/wip-cap/evaluate.js +3 -0
- package/package.json +35 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const SUBSCRIPTION_HISTORY_REL_PATH = "vbrief/.
|
|
1
|
+
export declare const SUBSCRIPTION_HISTORY_REL_PATH = "vbrief/.triage-cache/subscription-history.jsonl";
|
|
2
2
|
export declare const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
|
|
3
3
|
export declare const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
|
|
4
4
|
/** Python ``!r``-style quoting for parity with triage_subscribe.py messages. */
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
3
3
|
import { basename, join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveProjectDefinitionPath } from "../../layout/resolve.js";
|
|
5
5
|
import { migrateLegacyPolicyKey, PLAN_POLICY_KEY } from "../../policy/plan-extensions.js";
|
|
6
6
|
import { projectDefinitionMutationLock } from "../../vbrief-build/project-definition-io.js";
|
|
7
|
-
|
|
7
|
+
import { resolveTriageCachePath } from "../cache-path.js";
|
|
8
|
+
export const SUBSCRIPTION_HISTORY_REL_PATH = "vbrief/.triage-cache/subscription-history.jsonl";
|
|
8
9
|
export const SUBSCRIPTION_HISTORY_SCHEMA = "deft.triage.subscription-change.v1";
|
|
9
10
|
export const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
|
|
10
11
|
/** Python ``!r``-style quoting for parity with triage_subscribe.py messages. */
|
|
@@ -90,7 +91,7 @@ function resolveActor(actor) {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
export function recordSubscriptionChange(projectRoot, options) {
|
|
93
|
-
const historyPath =
|
|
94
|
+
const historyPath = resolveTriageCachePath(projectRoot, "subscription-history.jsonl");
|
|
94
95
|
const record = {
|
|
95
96
|
schema: SUBSCRIPTION_HISTORY_SCHEMA,
|
|
96
97
|
change_id: randomUUID(),
|
|
@@ -4,9 +4,9 @@ export declare const MAX_LINE_CHARS = 120;
|
|
|
4
4
|
export { DEFAULT_WIP_CAP, PROJECT_DEFINITION_REL_PATH };
|
|
5
5
|
export declare const CACHE_DIR_NAME = ".deft-cache";
|
|
6
6
|
export declare const CACHE_SOURCE = "github-issue";
|
|
7
|
-
export declare const CANDIDATES_LOG_REL_PATH = "vbrief/.
|
|
7
|
+
export declare const CANDIDATES_LOG_REL_PATH = "vbrief/.triage-cache/candidates.jsonl";
|
|
8
8
|
export { latestDecisions, readAuditLog } from "../actions/candidates-log.js";
|
|
9
|
-
export declare const SUMMARY_HISTORY_REL_PATH = "vbrief/.
|
|
9
|
+
export declare const SUMMARY_HISTORY_REL_PATH = "vbrief/.triage-cache/summary-history.jsonl";
|
|
10
10
|
export declare const SUMMARY_HISTORY_SCHEMA = "deft.triage.summary.v1";
|
|
11
11
|
/** D2 repeat-suppression window for session-start triage one-liner (#1122 / #1279). */
|
|
12
12
|
export declare const D2_SUPPRESSION_WINDOW_HOURS = 4;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
|
|
3
3
|
import { join, resolve as pathResolve } from "node:path";
|
|
4
|
-
import { hasArtifactSuffix,
|
|
4
|
+
import { hasArtifactSuffix, resolveLifecycleFolder, resolveProjectDefinitionPath, } from "../../layout/resolve.js";
|
|
5
5
|
import { readPlanPolicy } from "../../policy/plan-extensions.js";
|
|
6
6
|
import { loadProjectDefinition, PROJECT_DEFINITION_REL_PATH } from "../../policy/resolve.js";
|
|
7
7
|
import { countVbriefWip, DEFAULT_WIP_CAP, resolveWipCap } from "../../policy/wip.js";
|
|
8
8
|
import { AUDIT_LOG_REL_PATH, latestDecisions, readAuditLog } from "../actions/candidates-log.js";
|
|
9
|
+
import { resolveCandidatesLogPath } from "../cache-path.js";
|
|
9
10
|
import { countReconcilable } from "./reconcilable.js";
|
|
10
11
|
import { computeScopeDriftTotal } from "./scope-drift.js";
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
@@ -17,7 +18,7 @@ export const CACHE_DIR_NAME = ".deft-cache";
|
|
|
17
18
|
export const CACHE_SOURCE = "github-issue";
|
|
18
19
|
export const CANDIDATES_LOG_REL_PATH = AUDIT_LOG_REL_PATH;
|
|
19
20
|
export { latestDecisions, readAuditLog } from "../actions/candidates-log.js";
|
|
20
|
-
export const SUMMARY_HISTORY_REL_PATH = "vbrief/.
|
|
21
|
+
export const SUMMARY_HISTORY_REL_PATH = "vbrief/.triage-cache/summary-history.jsonl";
|
|
21
22
|
export const SUMMARY_HISTORY_SCHEMA = "deft.triage.summary.v1";
|
|
22
23
|
/** D2 repeat-suppression window for session-start triage one-liner (#1122 / #1279). */
|
|
23
24
|
export const D2_SUPPRESSION_WINDOW_HOURS = 4;
|
|
@@ -189,7 +190,7 @@ export function isCachedIssueOpen(cacheRoot, repo, issueNumber) {
|
|
|
189
190
|
export function computeSummary(projectRoot, options = {}) {
|
|
190
191
|
const root = pathResolve(projectRoot);
|
|
191
192
|
const resolvedCacheRoot = options.cacheRoot ?? join(root, CACHE_DIR_NAME);
|
|
192
|
-
const resolvedLogPath = options.auditLogPath ??
|
|
193
|
+
const resolvedLogPath = options.auditLogPath ?? resolveCandidatesLogPath(root);
|
|
193
194
|
const cached = iterCachedIssues(resolvedCacheRoot);
|
|
194
195
|
const repos = [...new Set(cached.map(([repo]) => repo))].sort();
|
|
195
196
|
const wipCap = resolveWipCapInt(root);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Lifecycle folders scanned for reconcilable vBRIEFs (#1468). */
|
|
2
2
|
export declare const BACKFILL_FOLDERS: readonly ["proposed", "pending", "active"];
|
|
3
|
-
export declare const CANDIDATES_LOG_REL_PATH = "vbrief/.
|
|
3
|
+
export declare const CANDIDATES_LOG_REL_PATH = "vbrief/.triage-cache/candidates.jsonl";
|
|
4
4
|
/**
|
|
5
5
|
* Count reconcilable issues (#1468) — mirrors `triage_reconcile.count_reconcilable`.
|
|
6
6
|
*/
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { referenceTypeMatches } from "@deftai/directive-types";
|
|
4
|
-
import { hasArtifactSuffix,
|
|
4
|
+
import { hasArtifactSuffix, resolveLifecycleRoot } from "../../layout/resolve.js";
|
|
5
5
|
import { AUDIT_LOG_REL_PATH, readAuditLog } from "../actions/candidates-log.js";
|
|
6
|
+
import { resolveCandidatesLogPath } from "../cache-path.js";
|
|
6
7
|
/** Lifecycle folders scanned for reconcilable vBRIEFs (#1468). */
|
|
7
8
|
export const BACKFILL_FOLDERS = ["proposed", "pending", "active"];
|
|
8
9
|
export const CANDIDATES_LOG_REL_PATH = AUDIT_LOG_REL_PATH;
|
|
@@ -63,7 +64,7 @@ function auditKey(repo, issueNumber) {
|
|
|
63
64
|
*/
|
|
64
65
|
export function countReconcilable(projectRoot, options = {}) {
|
|
65
66
|
try {
|
|
66
|
-
const auditPath = options.auditLogPath ??
|
|
67
|
+
const auditPath = options.auditLogPath ?? resolveCandidatesLogPath(projectRoot);
|
|
67
68
|
const existing = existingAuditRefs(auditPath);
|
|
68
69
|
const defaultRepo = options.defaultRepo ?? null;
|
|
69
70
|
const keys = new Set();
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
export declare const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
|
|
2
1
|
export declare const CACHE_DIR_NAME = ".deft-cache";
|
|
3
2
|
export declare const CACHE_SOURCE = "github-issue";
|
|
4
|
-
export declare const CANDIDATES_RELPATH: readonly ["vbrief", ".
|
|
3
|
+
export declare const CANDIDATES_RELPATH: readonly ["vbrief", ".triage-cache", "candidates.jsonl"];
|
|
5
4
|
export declare const WIP_LIFECYCLE_DIRS: readonly ["pending", "active"];
|
|
6
5
|
export declare const AUDIT_LOG_REL_PATH = "meta/policy-changes.log";
|
|
7
|
-
export declare const DEFAULT_WIP_CAP =
|
|
6
|
+
export declare const DEFAULT_WIP_CAP = 20;
|
|
8
7
|
export declare const DEFAULT_RELIEF_AGE_DAYS = 30;
|
|
9
8
|
export declare const TRIAGE_SKILL_PATH = "skills/deft-directive-triage/SKILL.md";
|
|
10
9
|
export declare const WELCOME_AUDIT_TAG = "triage-welcome";
|
|
11
|
-
export declare const SUMMARY_HISTORY_REL_PATH = "vbrief/.
|
|
10
|
+
export declare const SUMMARY_HISTORY_REL_PATH = "vbrief/.triage-cache/summary-history.jsonl";
|
|
12
11
|
export declare const SUMMARY_HISTORY_SCHEMA = "deft.triage.summary.v1";
|
|
13
12
|
export declare const EMPTY_CACHE_LINE = "[triage] cache empty -- run task triage:bootstrap";
|
|
14
13
|
export declare const MAX_LINE_CHARS = 120;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
export const PROJECT_DEFINITION_REL_PATH = "vbrief/PROJECT-DEFINITION.vbrief.json";
|
|
2
1
|
export const CACHE_DIR_NAME = ".deft-cache";
|
|
3
2
|
export const CACHE_SOURCE = "github-issue";
|
|
4
|
-
export const CANDIDATES_RELPATH = ["vbrief", ".
|
|
3
|
+
export const CANDIDATES_RELPATH = ["vbrief", ".triage-cache", "candidates.jsonl"];
|
|
5
4
|
export const WIP_LIFECYCLE_DIRS = ["pending", "active"];
|
|
6
5
|
export const AUDIT_LOG_REL_PATH = "meta/policy-changes.log";
|
|
7
|
-
export const DEFAULT_WIP_CAP =
|
|
6
|
+
export const DEFAULT_WIP_CAP = 20;
|
|
8
7
|
export const DEFAULT_RELIEF_AGE_DAYS = 30;
|
|
9
8
|
export const TRIAGE_SKILL_PATH = "skills/deft-directive-triage/SKILL.md";
|
|
10
9
|
export const WELCOME_AUDIT_TAG = "triage-welcome";
|
|
11
|
-
export const SUMMARY_HISTORY_REL_PATH = "vbrief/.
|
|
10
|
+
export const SUMMARY_HISTORY_REL_PATH = "vbrief/.triage-cache/summary-history.jsonl";
|
|
12
11
|
export const SUMMARY_HISTORY_SCHEMA = "deft.triage.summary.v1";
|
|
13
12
|
export const EMPTY_CACHE_LINE = "[triage] cache empty -- run task triage:bootstrap";
|
|
14
13
|
export const MAX_LINE_CHARS = 120;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./constants.js";
|
|
2
2
|
export { type DefaultModeOptions, formatWelcomeCommand, normalizeTaskPrefix, runDefaultMode, type WelcomeOutcome, } from "./default-mode.js";
|
|
3
|
+
export { DEFAULT_ONBOARD_PRESET, type OnboardOptions, type OnboardOutcome, runOnboardMode, } from "./onboard.js";
|
|
3
4
|
export { candidatesLogPath, classifyOnboarding, detectPriorState, type PriorState, pendingDecisionsNudgeLine, } from "./prior-state.js";
|
|
4
5
|
export { computeSummary, emitOneliner, formatOneLiner, formatSummary, type SummaryResult, } from "./summary.js";
|
|
5
6
|
export { appendAuditEntry, previewWipRelief, type ReliefPreview, subscriptionPreset, writeTriageScope, writeWipCap, } from "./writers.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from "./constants.js";
|
|
2
2
|
export { formatWelcomeCommand, normalizeTaskPrefix, runDefaultMode, } from "./default-mode.js";
|
|
3
|
+
export { DEFAULT_ONBOARD_PRESET, runOnboardMode, } from "./onboard.js";
|
|
3
4
|
export { candidatesLogPath, classifyOnboarding, detectPriorState, pendingDecisionsNudgeLine, } from "./prior-state.js";
|
|
4
5
|
export { computeSummary, emitOneliner, formatOneLiner, formatSummary, } from "./summary.js";
|
|
5
6
|
export { appendAuditEntry, previewWipRelief, subscriptionPreset, writeTriageScope, writeWipCap, } from "./writers.js";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Default triage-scope preset applied when `--onboard` is run without `--preset`. */
|
|
2
|
+
export declare const DEFAULT_ONBOARD_PRESET = "small";
|
|
3
|
+
export interface OnboardOptions {
|
|
4
|
+
/** Triage-scope preset key; defaults to {@link DEFAULT_ONBOARD_PRESET}. */
|
|
5
|
+
readonly preset?: string | null;
|
|
6
|
+
/** Explicit WIP cap to persist; omitted keeps the current/default cap. */
|
|
7
|
+
readonly wipCap?: number | null;
|
|
8
|
+
readonly output?: (line: string) => void;
|
|
9
|
+
readonly writeHistory?: boolean;
|
|
10
|
+
readonly taskPrefix?: string | null;
|
|
11
|
+
readonly selfHealFn?: (projectRoot: string) => void;
|
|
12
|
+
readonly now?: Date;
|
|
13
|
+
}
|
|
14
|
+
export interface OnboardOutcome {
|
|
15
|
+
readonly exitCode: number;
|
|
16
|
+
readonly presetApplied: string | null;
|
|
17
|
+
readonly triageScopeChanged: boolean;
|
|
18
|
+
readonly wipCapApplied: number | null;
|
|
19
|
+
readonly wipCapChanged: boolean;
|
|
20
|
+
readonly reliefOffered: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Non-interactive onboarding for `deft triage:welcome --onboard` (#2295).
|
|
24
|
+
*
|
|
25
|
+
* The welcome nudges point every fresh consumer at `--onboard`; this wires that
|
|
26
|
+
* command to the already-tested core writers instead of the old "not
|
|
27
|
+
* implemented" stub. It writes the chosen triage-scope preset and (optionally)
|
|
28
|
+
* a WIP cap via {@link writeTriageScope} / {@link writeWipCap} -- which already
|
|
29
|
+
* target the canonical `x-directive/policy` key and migrate any legacy bare
|
|
30
|
+
* block -- previews WIP relief when at/over cap, then prints a completion
|
|
31
|
+
* summary and the next-step guidance. Flag-driven by design: agents/CI pass
|
|
32
|
+
* `--preset` / `--wip-cap`; sensible defaults apply otherwise.
|
|
33
|
+
*/
|
|
34
|
+
export declare function runOnboardMode(projectRoot: string, options?: OnboardOptions): OnboardOutcome;
|
|
35
|
+
//# sourceMappingURL=onboard.d.ts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { maybeSelfHealCache } from "../../cache/fetch.js";
|
|
4
|
+
import { resolveProjectDefinitionPath } from "../../layout/resolve.js";
|
|
5
|
+
import { DEFAULT_WIP_CAP, SUBSCRIPTION_PRESETS, TRIAGE_SKILL_PATH } from "./constants.js";
|
|
6
|
+
import { formatWelcomeCommand } from "./default-mode.js";
|
|
7
|
+
import { detectPriorState } from "./prior-state.js";
|
|
8
|
+
import { emitOneliner } from "./summary.js";
|
|
9
|
+
import { previewWipRelief, subscriptionPreset, writeTriageScope, writeWipCap } from "./writers.js";
|
|
10
|
+
/** Default triage-scope preset applied when `--onboard` is run without `--preset`. */
|
|
11
|
+
export const DEFAULT_ONBOARD_PRESET = "small";
|
|
12
|
+
function failure(exitCode) {
|
|
13
|
+
return {
|
|
14
|
+
exitCode,
|
|
15
|
+
presetApplied: null,
|
|
16
|
+
triageScopeChanged: false,
|
|
17
|
+
wipCapApplied: null,
|
|
18
|
+
wipCapChanged: false,
|
|
19
|
+
reliefOffered: false,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Non-interactive onboarding for `deft triage:welcome --onboard` (#2295).
|
|
24
|
+
*
|
|
25
|
+
* The welcome nudges point every fresh consumer at `--onboard`; this wires that
|
|
26
|
+
* command to the already-tested core writers instead of the old "not
|
|
27
|
+
* implemented" stub. It writes the chosen triage-scope preset and (optionally)
|
|
28
|
+
* a WIP cap via {@link writeTriageScope} / {@link writeWipCap} -- which already
|
|
29
|
+
* target the canonical `x-directive/policy` key and migrate any legacy bare
|
|
30
|
+
* block -- previews WIP relief when at/over cap, then prints a completion
|
|
31
|
+
* summary and the next-step guidance. Flag-driven by design: agents/CI pass
|
|
32
|
+
* `--preset` / `--wip-cap`; sensible defaults apply otherwise.
|
|
33
|
+
*/
|
|
34
|
+
export function runOnboardMode(projectRoot, options = {}) {
|
|
35
|
+
const out = options.output ?? ((line) => process.stdout.write(`${line}\n`));
|
|
36
|
+
const preset = (options.preset ?? DEFAULT_ONBOARD_PRESET).trim() || DEFAULT_ONBOARD_PRESET;
|
|
37
|
+
if (!Object.hasOwn(SUBSCRIPTION_PRESETS, preset)) {
|
|
38
|
+
out(`[welcome] Unknown --preset '${preset}'. Choose one of: ${Object.keys(SUBSCRIPTION_PRESETS).join(", ")}.`);
|
|
39
|
+
return failure(2);
|
|
40
|
+
}
|
|
41
|
+
const wipCap = options.wipCap ?? null;
|
|
42
|
+
if (wipCap !== null && (!Number.isInteger(wipCap) || wipCap < 1)) {
|
|
43
|
+
out(`[welcome] --wip-cap must be a positive integer, got ${JSON.stringify(options.wipCap)}.`);
|
|
44
|
+
return failure(2);
|
|
45
|
+
}
|
|
46
|
+
const pdPath = resolveProjectDefinitionPath(projectRoot);
|
|
47
|
+
if (!existsSync(pdPath)) {
|
|
48
|
+
out(`[welcome] No project definition found at ${pdPath}. Run project setup first (deft-directive-setup) before onboarding triage.`);
|
|
49
|
+
return failure(2);
|
|
50
|
+
}
|
|
51
|
+
const heal = options.selfHealFn ??
|
|
52
|
+
((root) => {
|
|
53
|
+
maybeSelfHealCache(resolve(root));
|
|
54
|
+
});
|
|
55
|
+
heal(projectRoot);
|
|
56
|
+
const rules = subscriptionPreset(preset);
|
|
57
|
+
const [triageScopeChanged] = writeTriageScope(projectRoot, rules, { presetLabel: preset });
|
|
58
|
+
let wipCapChanged = false;
|
|
59
|
+
if (wipCap !== null) {
|
|
60
|
+
[wipCapChanged] = writeWipCap(projectRoot, wipCap);
|
|
61
|
+
}
|
|
62
|
+
emitOneliner(projectRoot, {
|
|
63
|
+
writeHistory: options.writeHistory !== false,
|
|
64
|
+
now: options.now,
|
|
65
|
+
output: out,
|
|
66
|
+
applyD2Suppression: false,
|
|
67
|
+
});
|
|
68
|
+
const state = detectPriorState(projectRoot);
|
|
69
|
+
let reliefOffered = false;
|
|
70
|
+
if (state.wipCount >= state.wipCap) {
|
|
71
|
+
const relief = previewWipRelief(projectRoot);
|
|
72
|
+
if (relief.eligibleCount > 0) {
|
|
73
|
+
reliefOffered = true;
|
|
74
|
+
const demote = formatWelcomeCommand(["scope:demote", "--batch", "--older-than-days", String(relief.olderThanDays)], options.taskPrefix).replace(/\r?\n/g, " ");
|
|
75
|
+
const eligibleCount = String(relief.eligibleCount).replace(/\r?\n/g, " ");
|
|
76
|
+
out(`[welcome] WIP ${state.wipCount}/${state.wipCap} at/over cap -- ${eligibleCount} pending scope(s) ` +
|
|
77
|
+
`older than ${relief.olderThanDays}d are demote-eligible. Relieve with \`${demote}\`.`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const capNote = wipCap !== null ? `, wipCap ${wipCap}` : ` (wipCap default ${DEFAULT_WIP_CAP})`;
|
|
81
|
+
out(`[welcome] Onboarding applied: triage scope preset '${preset}'${capNote}.`);
|
|
82
|
+
const bootstrap = formatWelcomeCommand(["triage:bootstrap"], options.taskPrefix);
|
|
83
|
+
const queue = formatWelcomeCommand(["triage:queue", "--limit=10"], options.taskPrefix);
|
|
84
|
+
out(`[welcome] Next: run \`${bootstrap}\` to populate the triage cache, then \`${queue}\` to pick work. See ${TRIAGE_SKILL_PATH}.`);
|
|
85
|
+
return {
|
|
86
|
+
exitCode: 0,
|
|
87
|
+
presetApplied: preset,
|
|
88
|
+
triageScopeChanged,
|
|
89
|
+
wipCapApplied: wipCap,
|
|
90
|
+
wipCapChanged,
|
|
91
|
+
reliefOffered,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=onboard.js.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
import { hasArtifactSuffix, resolveAuditPath,
|
|
3
|
+
import { hasArtifactSuffix, resolveAuditPath, resolveLifecycleRoot, resolveProjectDefinitionPath, } from "../../layout/resolve.js";
|
|
4
4
|
import { readPlanPolicy } from "../../policy/plan-extensions.js";
|
|
5
|
+
import { resolveCandidatesLogPath } from "../cache-path.js";
|
|
5
6
|
import { CACHE_DIR_NAME, CACHE_SOURCE, DEFAULT_WIP_CAP, SUBSCRIPTION_PRESETS, WIP_LIFECYCLE_DIRS, } from "./constants.js";
|
|
6
7
|
function loadProjectDefinition(projectRoot) {
|
|
7
8
|
const path = resolveProjectDefinitionPath(projectRoot);
|
|
@@ -39,7 +40,7 @@ function countCacheEntries(projectRoot) {
|
|
|
39
40
|
return count;
|
|
40
41
|
}
|
|
41
42
|
export function candidatesLogPath(projectRoot) {
|
|
42
|
-
return
|
|
43
|
+
return resolveCandidatesLogPath(projectRoot);
|
|
43
44
|
}
|
|
44
45
|
function countWip(projectRoot) {
|
|
45
46
|
let total = 0;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from "node:fs";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
|
-
import { hasArtifactSuffix,
|
|
3
|
+
import { hasArtifactSuffix, resolveLifecycleFolder, resolveProjectDefinitionPath, } from "../../layout/resolve.js";
|
|
4
4
|
import { readPlanPolicy } from "../../policy/plan-extensions.js";
|
|
5
|
-
import { countVbriefWip,
|
|
5
|
+
import { countVbriefWip, resolveWipCap } from "../../policy/wip.js";
|
|
6
|
+
import { resolveCandidatesLogPath, resolveTriageCachePath } from "../cache-path.js";
|
|
6
7
|
import { countReconcilable } from "../reconcile/reconcile.js";
|
|
7
8
|
import { computeDrift } from "../scope-drift/compute.js";
|
|
8
9
|
import { shouldSuppressD2Emission } from "../summary/index.js";
|
|
@@ -119,7 +120,7 @@ function utcIso() {
|
|
|
119
120
|
export function computeSummary(projectRoot) {
|
|
120
121
|
const root = resolve(projectRoot);
|
|
121
122
|
const cacheRoot = join(root, CACHE_DIR_NAME);
|
|
122
|
-
const logPath =
|
|
123
|
+
const logPath = resolveCandidatesLogPath(root);
|
|
123
124
|
const cached = iterCachedIssues(cacheRoot);
|
|
124
125
|
const repos = [...new Set(cached.map(([r]) => r))].sort().slice(0, 8);
|
|
125
126
|
const wipCapResult = resolveWipCap(root);
|
|
@@ -293,7 +294,7 @@ export function appendHistory(historyPath, result, line) {
|
|
|
293
294
|
export function emitOneliner(projectRoot, options = {}) {
|
|
294
295
|
const result = computeSummary(projectRoot);
|
|
295
296
|
const line = formatSummary(result);
|
|
296
|
-
const historyPath =
|
|
297
|
+
const historyPath = resolveTriageCachePath(projectRoot, "summary-history.jsonl");
|
|
297
298
|
const applySuppression = options.applyD2Suppression !== false;
|
|
298
299
|
if (applySuppression && shouldSuppressD2Emission(result, historyPath, { now: options.now })) {
|
|
299
300
|
return line;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #2307: only comments authored by a repo maintainer may be treated as the
|
|
3
|
+
* authoritative current-shape state. GitHub's `author_association` on an issue
|
|
4
|
+
* comment is the trust signal; anything outside this set (CONTRIBUTOR, NONE,
|
|
5
|
+
* FIRST_TIME_CONTRIBUTOR, ...) is an untrusted third party and cannot forge a
|
|
6
|
+
* higher-pass current-shape comment.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MAINTAINER_ASSOCIATIONS: ReadonlySet<string>;
|
|
9
|
+
/** True when a comment's author_association marks it as maintainer-authored (#2307). */
|
|
10
|
+
export declare function isMaintainerAuthored(association: string): boolean;
|
|
1
11
|
/** Matches `## Current shape (as of pass-N)` — same pattern as vbrief-reconcile/umbrellas.ts. */
|
|
2
12
|
export declare const CURRENT_SHAPE_HEADER_RE: RegExp;
|
|
3
13
|
export declare const SECTION_MARKERS: {
|
|
@@ -20,6 +30,8 @@ export interface IssueComment {
|
|
|
20
30
|
readonly body: string;
|
|
21
31
|
readonly htmlUrl: string;
|
|
22
32
|
readonly updatedAt: string;
|
|
33
|
+
readonly authorLogin: string;
|
|
34
|
+
readonly authorAssociation: string;
|
|
23
35
|
}
|
|
24
36
|
export interface CurrentShapeComment extends IssueComment {
|
|
25
37
|
readonly pass: number;
|
|
@@ -37,6 +49,8 @@ export interface CurrentShapeResult {
|
|
|
37
49
|
readonly htmlUrl: string;
|
|
38
50
|
readonly pass: number;
|
|
39
51
|
readonly body: string;
|
|
52
|
+
readonly authorLogin: string;
|
|
53
|
+
readonly authorAssociation: string;
|
|
40
54
|
readonly sections: SectionPresence;
|
|
41
55
|
}
|
|
42
56
|
export type ScmFetcher = (repo: string, issueNumber: number) => IssueComment[] | {
|
|
@@ -55,11 +69,20 @@ export interface RunCurrentShapeOptions {
|
|
|
55
69
|
/** Merge `gh api --paginate` concatenated JSON array pages into comment rows. */
|
|
56
70
|
export declare function parseCommentsFromGhStdout(stdout: string): IssueComment[];
|
|
57
71
|
export declare function extractPassFromBody(body: string): number | null;
|
|
58
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Pick the canonical comment — highest pass-N; tie-break by comment id (latest).
|
|
74
|
+
*
|
|
75
|
+
* #2307: only MAINTAINER-authored comments (author_association in
|
|
76
|
+
* {OWNER, MEMBER, COLLABORATOR}) are eligible. A non-maintainer higher-pass
|
|
77
|
+
* comment is ignored, which defeats the forged-higher-pass primitive: an
|
|
78
|
+
* attacker cannot inject authoritative state by simply commenting with a bigger
|
|
79
|
+
* pass number.
|
|
80
|
+
*/
|
|
59
81
|
export declare function selectCurrentShapeComment(comments: readonly IssueComment[]): CurrentShapeComment | null;
|
|
60
82
|
export declare function detectSections(body: string): SectionPresence;
|
|
61
83
|
export declare function sectionsRecord(presence: SectionPresence): Record<string, boolean>;
|
|
62
84
|
export declare const NO_CURRENT_SHAPE_MESSAGE: string;
|
|
85
|
+
export declare const NON_MAINTAINER_CURRENT_SHAPE_MESSAGE: string;
|
|
63
86
|
export declare function fetchCurrentShape(options: {
|
|
64
87
|
repo: string;
|
|
65
88
|
issueNumber: number;
|
|
@@ -75,6 +98,7 @@ export declare function fetchCurrentShape(options: {
|
|
|
75
98
|
export declare function emitCurrentShape(result: CurrentShapeResult, options: {
|
|
76
99
|
jsonMode: boolean;
|
|
77
100
|
writeOut: (text: string) => void;
|
|
101
|
+
writeErr?: (text: string) => void;
|
|
78
102
|
}): number;
|
|
79
103
|
export declare function runCurrentShape(options: RunCurrentShapeOptions): number;
|
|
80
104
|
export declare function parseCurrentShapeArgv(argv: readonly string[]): {
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { scan } from "../cache/scanner.js";
|
|
2
3
|
import { resolveBinary } from "../scm/binary.js";
|
|
3
4
|
import { SUBPROCESS_MAX_BUFFER } from "../subprocess/max-buffer.js";
|
|
4
5
|
import { resolveRepo } from "../triage/queue/repo.js";
|
|
6
|
+
/**
|
|
7
|
+
* #2307: only comments authored by a repo maintainer may be treated as the
|
|
8
|
+
* authoritative current-shape state. GitHub's `author_association` on an issue
|
|
9
|
+
* comment is the trust signal; anything outside this set (CONTRIBUTOR, NONE,
|
|
10
|
+
* FIRST_TIME_CONTRIBUTOR, ...) is an untrusted third party and cannot forge a
|
|
11
|
+
* higher-pass current-shape comment.
|
|
12
|
+
*/
|
|
13
|
+
export const MAINTAINER_ASSOCIATIONS = new Set([
|
|
14
|
+
"OWNER",
|
|
15
|
+
"MEMBER",
|
|
16
|
+
"COLLABORATOR",
|
|
17
|
+
]);
|
|
18
|
+
/** True when a comment's author_association marks it as maintainer-authored (#2307). */
|
|
19
|
+
export function isMaintainerAuthored(association) {
|
|
20
|
+
return MAINTAINER_ASSOCIATIONS.has(association.toUpperCase());
|
|
21
|
+
}
|
|
5
22
|
/** Matches `## Current shape (as of pass-N)` — same pattern as vbrief-reconcile/umbrellas.ts. */
|
|
6
23
|
export const CURRENT_SHAPE_HEADER_RE = /^## Current shape \(as of pass-(\d+)\)/m;
|
|
7
24
|
export const SECTION_MARKERS = {
|
|
@@ -35,11 +52,16 @@ function mapCommentEntry(entry) {
|
|
|
35
52
|
if (typeof rec.id !== "number" || typeof rec.body !== "string") {
|
|
36
53
|
return null;
|
|
37
54
|
}
|
|
55
|
+
const user = typeof rec.user === "object" && rec.user !== null
|
|
56
|
+
? rec.user
|
|
57
|
+
: null;
|
|
38
58
|
return {
|
|
39
59
|
id: rec.id,
|
|
40
60
|
body: rec.body,
|
|
41
61
|
htmlUrl: typeof rec.html_url === "string" ? rec.html_url : "",
|
|
42
62
|
updatedAt: typeof rec.updated_at === "string" ? rec.updated_at : "",
|
|
63
|
+
authorLogin: user !== null && typeof user.login === "string" ? user.login : "",
|
|
64
|
+
authorAssociation: typeof rec.author_association === "string" ? rec.author_association : "",
|
|
43
65
|
};
|
|
44
66
|
}
|
|
45
67
|
/** Merge `gh api --paginate` concatenated JSON array pages into comment rows. */
|
|
@@ -135,10 +157,21 @@ export function extractPassFromBody(body) {
|
|
|
135
157
|
const pass = Number(match[1]);
|
|
136
158
|
return Number.isFinite(pass) ? pass : null;
|
|
137
159
|
}
|
|
138
|
-
/**
|
|
160
|
+
/**
|
|
161
|
+
* Pick the canonical comment — highest pass-N; tie-break by comment id (latest).
|
|
162
|
+
*
|
|
163
|
+
* #2307: only MAINTAINER-authored comments (author_association in
|
|
164
|
+
* {OWNER, MEMBER, COLLABORATOR}) are eligible. A non-maintainer higher-pass
|
|
165
|
+
* comment is ignored, which defeats the forged-higher-pass primitive: an
|
|
166
|
+
* attacker cannot inject authoritative state by simply commenting with a bigger
|
|
167
|
+
* pass number.
|
|
168
|
+
*/
|
|
139
169
|
export function selectCurrentShapeComment(comments) {
|
|
140
170
|
let best = null;
|
|
141
171
|
for (const comment of comments) {
|
|
172
|
+
if (!isMaintainerAuthored(comment.authorAssociation)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
142
175
|
const pass = extractPassFromBody(comment.body);
|
|
143
176
|
if (pass === null) {
|
|
144
177
|
continue;
|
|
@@ -188,6 +221,16 @@ export function sectionsRecord(presence) {
|
|
|
188
221
|
export const NO_CURRENT_SHAPE_MESSAGE = "No ## Current shape (as of pass-N) comment found on this issue. " +
|
|
189
222
|
"Create one per AGENTS.md ## Umbrella current-shape convention (#1152) — " +
|
|
190
223
|
"do not fall back to the issue body (stale by design).";
|
|
224
|
+
// #2307 (Greptile review): a structurally valid current-shape comment authored
|
|
225
|
+
// by a non-maintainer is filtered out for provenance and would otherwise be
|
|
226
|
+
// reported with the generic "not found" message above -- indistinguishable from
|
|
227
|
+
// genuine absence, which makes --strict especially confusing to debug. This
|
|
228
|
+
// message names the provenance filter explicitly so the caller knows the
|
|
229
|
+
// comment exists but was ignored, not that it is missing.
|
|
230
|
+
export const NON_MAINTAINER_CURRENT_SHAPE_MESSAGE = "A ## Current shape (as of pass-N) comment exists but was authored by a " +
|
|
231
|
+
"non-maintainer (author_association not in OWNER/MEMBER/COLLABORATOR) and is " +
|
|
232
|
+
"ignored per AGENTS.md ## Umbrella current-shape convention (#1152 / #2307). " +
|
|
233
|
+
"A maintainer must (re-)post the current-shape comment for it to be authoritative.";
|
|
191
234
|
export function fetchCurrentShape(options) {
|
|
192
235
|
const fetcher = options.fetchComments ?? defaultFetchComments;
|
|
193
236
|
const fetched = fetcher(options.repo, options.issueNumber);
|
|
@@ -196,7 +239,15 @@ export function fetchCurrentShape(options) {
|
|
|
196
239
|
}
|
|
197
240
|
const selected = selectCurrentShapeComment(fetched);
|
|
198
241
|
if (selected === null) {
|
|
199
|
-
|
|
242
|
+
// Distinguish provenance-filtered absence from genuine absence (#2307).
|
|
243
|
+
const hadNonMaintainerShape = fetched.some((c) => extractPassFromBody(c.body) !== null && !isMaintainerAuthored(c.authorAssociation));
|
|
244
|
+
return {
|
|
245
|
+
ok: false,
|
|
246
|
+
error: hadNonMaintainerShape
|
|
247
|
+
? NON_MAINTAINER_CURRENT_SHAPE_MESSAGE
|
|
248
|
+
: NO_CURRENT_SHAPE_MESSAGE,
|
|
249
|
+
kind: "not-found",
|
|
250
|
+
};
|
|
200
251
|
}
|
|
201
252
|
const sections = detectSections(selected.body);
|
|
202
253
|
return {
|
|
@@ -208,11 +259,36 @@ export function fetchCurrentShape(options) {
|
|
|
208
259
|
htmlUrl: selected.htmlUrl,
|
|
209
260
|
pass: selected.pass,
|
|
210
261
|
body: selected.body,
|
|
262
|
+
authorLogin: selected.authorLogin,
|
|
263
|
+
authorAssociation: selected.authorAssociation,
|
|
211
264
|
sections,
|
|
212
265
|
},
|
|
213
266
|
};
|
|
214
267
|
}
|
|
215
268
|
export function emitCurrentShape(result, options) {
|
|
269
|
+
// #2307: the selected comment body is still attacker-influencable text (a
|
|
270
|
+
// maintainer can quote/paste untrusted content). Run it through the same
|
|
271
|
+
// quarantine scanner used for cache content and emit the fenced transform so
|
|
272
|
+
// injection-shaped sections are quarantined, never rendered as authoritative
|
|
273
|
+
// instructions.
|
|
274
|
+
const scanned = scan(result.body);
|
|
275
|
+
// #2307 fail-closed (Greptile review): a scanner hard-fail (e.g. a credential
|
|
276
|
+
// pattern) is only FLAGGED by scan() -- detectCredentials sets passed=false
|
|
277
|
+
// but does NOT redact the secret from transformed_content. Emitting the
|
|
278
|
+
// transform regardless would forward the raw credential to stdout / CI logs /
|
|
279
|
+
// JSON consumers. Mirror buildIssueVbrief (#2306, issue:ingest), which throws
|
|
280
|
+
// ScannerHardFailError and writes nothing: refuse to emit and return non-zero.
|
|
281
|
+
if (!scanned.passed) {
|
|
282
|
+
const details = scanned.flags
|
|
283
|
+
.filter((f) => f.severity === "hard-fail")
|
|
284
|
+
.map((f) => f.detail)
|
|
285
|
+
.join("; ");
|
|
286
|
+
const writeErr = options.writeErr ?? ((text) => process.stderr.write(text));
|
|
287
|
+
writeErr(`umbrella:current-shape: refused issue #${result.issueNumber}: quarantine scanner hard-fail` +
|
|
288
|
+
(details.length > 0 ? ` (${details})` : "") +
|
|
289
|
+
" -- nothing written.\n");
|
|
290
|
+
return 1;
|
|
291
|
+
}
|
|
216
292
|
if (options.jsonMode) {
|
|
217
293
|
const payload = {
|
|
218
294
|
issueNumber: result.issueNumber,
|
|
@@ -220,7 +296,10 @@ export function emitCurrentShape(result, options) {
|
|
|
220
296
|
commentId: result.commentId,
|
|
221
297
|
htmlUrl: result.htmlUrl,
|
|
222
298
|
pass: result.pass,
|
|
223
|
-
body:
|
|
299
|
+
body: scanned.transformed_content,
|
|
300
|
+
authorLogin: result.authorLogin,
|
|
301
|
+
authorAssociation: result.authorAssociation,
|
|
302
|
+
scannerPassed: scanned.passed,
|
|
224
303
|
sections: sectionsRecord(result.sections),
|
|
225
304
|
missingSections: result.sections.missing,
|
|
226
305
|
missingOptionalSections: result.sections.optionalMissing,
|
|
@@ -228,7 +307,7 @@ export function emitCurrentShape(result, options) {
|
|
|
228
307
|
options.writeOut(`${JSON.stringify(payload)}\n`);
|
|
229
308
|
}
|
|
230
309
|
else {
|
|
231
|
-
options.writeOut(`${
|
|
310
|
+
options.writeOut(`${scanned.transformed_content}\n`);
|
|
232
311
|
}
|
|
233
312
|
return 0;
|
|
234
313
|
}
|
|
@@ -260,6 +339,7 @@ export function runCurrentShape(options) {
|
|
|
260
339
|
return emitCurrentShape(fetched.result, {
|
|
261
340
|
jsonMode: options.jsonMode ?? false,
|
|
262
341
|
writeOut,
|
|
342
|
+
writeErr,
|
|
263
343
|
});
|
|
264
344
|
}
|
|
265
345
|
export function parseCurrentShapeArgv(argv) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ValueFeedbackResolved } from "../policy/value-feedback.js";
|
|
2
|
+
import { type WorkContext } from "./adoption-registry.js";
|
|
3
|
+
export interface AdoptionEmitOptions {
|
|
4
|
+
readonly logPath?: string | null;
|
|
5
|
+
readonly policyOverride?: ValueFeedbackResolved;
|
|
6
|
+
readonly workContext?: WorkContext;
|
|
7
|
+
}
|
|
8
|
+
/** Best-effort WorkContext snapshot from git porcelain status (#2339). */
|
|
9
|
+
export declare function buildWorkContextFromGit(projectRoot: string): WorkContext;
|
|
10
|
+
/** Record adoption signals for applicable-but-unused capabilities (#2339). */
|
|
11
|
+
export declare function recordAdoptionSignalsFromWorkContext(projectRoot: string, ctx: WorkContext, options?: AdoptionEmitOptions): number;
|
|
12
|
+
/** Session/work-boundary adoption probe — builds WorkContext when omitted (#2339). */
|
|
13
|
+
export declare function probeAdoptionAtWorkBoundary(projectRoot: string, options?: AdoptionEmitOptions): number;
|
|
14
|
+
//# sourceMappingURL=adoption-emit.d.ts.map
|