@deftai/directive-core 0.89.0 → 0.91.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/doctor/constants.d.ts +1 -1
- package/dist/doctor/constants.js +2 -0
- package/dist/doctor/flags.js +21 -1
- package/dist/doctor/index.d.ts +1 -0
- package/dist/doctor/index.js +1 -0
- package/dist/doctor/main.js +22 -0
- package/dist/doctor/openclaw-skills.d.ts +143 -0
- package/dist/doctor/openclaw-skills.js +706 -0
- package/dist/doctor/types.d.ts +11 -0
- package/dist/eval/health.d.ts +10 -1
- package/dist/eval/health.js +16 -16
- package/dist/hooks/dispatcher.js +20 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/init-deposit/hygiene.js +3 -0
- package/dist/init-deposit/init-deposit.d.ts +5 -0
- package/dist/init-deposit/init-deposit.js +37 -2
- package/dist/intake/github-auth-modes.d.ts +1 -1
- package/dist/intake/github-auth-modes.js +25 -3
- package/dist/intake/issue-ingest-cli.js +13 -0
- package/dist/intake/reconcile-issues-cli.js +13 -0
- package/dist/lifecycle/events.js +2 -0
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.js +1 -0
- package/dist/lifecycle/stats.d.ts +53 -0
- package/dist/lifecycle/stats.js +286 -0
- package/dist/policy/plan-extensions.d.ts +10 -0
- package/dist/policy/plan-extensions.js +16 -0
- package/dist/pr-closing-keywords/detect.d.ts +13 -0
- package/dist/pr-closing-keywords/detect.js +73 -8
- package/dist/pr-closing-keywords/index.d.ts +2 -2
- package/dist/pr-closing-keywords/index.js +1 -1
- package/dist/pr-closing-keywords/main.js +119 -90
- package/dist/pr-closing-keywords/types.d.ts +10 -0
- package/dist/release/spawn.js +13 -0
- package/dist/release-e2e/git-ops.d.ts +7 -0
- package/dist/release-e2e/git-ops.js +35 -2
- package/dist/render/constants.d.ts +16 -0
- package/dist/render/constants.js +16 -1
- package/dist/render/export-spec.d.ts +7 -1
- package/dist/render/export-spec.js +51 -5
- package/dist/render/index.d.ts +3 -2
- package/dist/render/index.js +2 -2
- package/dist/render/roadmap-render.js +164 -60
- package/dist/render/scope-outlook.d.ts +5 -0
- package/dist/render/scope-outlook.js +3 -0
- package/dist/render/spec-render.d.ts +28 -2
- package/dist/render/spec-render.js +111 -14
- package/dist/render/text-utils.d.ts +6 -0
- package/dist/render/text-utils.js +23 -0
- package/dist/scm/binary.d.ts +3 -0
- package/dist/scm/binary.js +10 -2
- package/dist/scm/call.d.ts +5 -0
- package/dist/scm/call.js +5 -0
- package/dist/scm/index.d.ts +1 -0
- package/dist/scm/index.js +1 -0
- package/dist/scm/main.d.ts +5 -0
- package/dist/scm/main.js +27 -0
- package/dist/scm/readiness-cli.d.ts +24 -0
- package/dist/scm/readiness-cli.js +85 -0
- package/dist/scm/readiness.d.ts +104 -0
- package/dist/scm/readiness.js +421 -0
- package/dist/scope/batch-promote.d.ts +26 -0
- package/dist/scope/batch-promote.js +167 -0
- package/dist/scope/index.d.ts +1 -0
- package/dist/scope/index.js +1 -0
- package/dist/scope/main.d.ts +2 -0
- package/dist/scope/main.js +58 -7
- package/dist/scope/wip-cap-check.d.ts +6 -0
- package/dist/scope/wip-cap-check.js +14 -2
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +2 -0
- package/dist/session/process-cost-constants.d.ts +9 -0
- package/dist/session/process-cost-constants.js +11 -0
- package/dist/session/process-cost.d.ts +53 -0
- package/dist/session/process-cost.js +82 -0
- package/dist/session/ritual-sentinel.d.ts +5 -0
- package/dist/session/ritual-sentinel.js +12 -1
- package/dist/session/session-ready.d.ts +67 -0
- package/dist/session/session-ready.js +264 -0
- package/dist/session/session-start.d.ts +63 -1
- package/dist/session/session-start.js +432 -24
- package/dist/session/verify-session-ritual.d.ts +8 -0
- package/dist/session/verify-session-ritual.js +95 -35
- package/dist/tool-events/classify.d.ts +20 -0
- package/dist/tool-events/classify.js +634 -0
- package/dist/tool-events/index.d.ts +10 -0
- package/dist/tool-events/index.js +10 -0
- package/dist/tool-events/summarize.d.ts +34 -0
- package/dist/tool-events/summarize.js +93 -0
- package/dist/tool-events/types.d.ts +52 -0
- package/dist/tool-events/types.js +13 -0
- package/dist/triage/welcome/index.d.ts +1 -1
- package/dist/triage/welcome/index.js +1 -1
- package/dist/triage/welcome/onboard.js +7 -1
- package/dist/triage/welcome/prior-state.d.ts +7 -0
- package/dist/triage/welcome/prior-state.js +16 -2
- package/dist/triage/welcome/writers.d.ts +10 -0
- package/dist/triage/welcome/writers.js +72 -2
- package/package.json +7 -3
package/dist/doctor/types.d.ts
CHANGED
|
@@ -75,6 +75,10 @@ export interface DoctorFlags {
|
|
|
75
75
|
readonly network: boolean;
|
|
76
76
|
readonly help: boolean;
|
|
77
77
|
readonly projectRoot: string | null;
|
|
78
|
+
/** Replace divergent OpenClaw pin dirs during doctor --fix (#3001). */
|
|
79
|
+
readonly force: boolean;
|
|
80
|
+
/** Wire always-pins into main + every workspace-* seat (#3001). */
|
|
81
|
+
readonly openclawAllAgents: boolean;
|
|
78
82
|
readonly unknown: readonly string[];
|
|
79
83
|
}
|
|
80
84
|
export interface ThrottleDecision {
|
|
@@ -161,5 +165,12 @@ export interface DoctorSeams {
|
|
|
161
165
|
readonly distance: "current" | "behind-minor" | "behind-major";
|
|
162
166
|
readonly stale: boolean;
|
|
163
167
|
};
|
|
168
|
+
/**
|
|
169
|
+
* OpenClaw skill-pin seams (#3001). Injected so detect/fix stays offline +
|
|
170
|
+
* deterministic in tests (fake HOME / env / fs).
|
|
171
|
+
*/
|
|
172
|
+
readonly openclawEnv?: NodeJS.ProcessEnv;
|
|
173
|
+
readonly openclawHomeDir?: () => string;
|
|
174
|
+
readonly openclawContentRootFor?: (frameworkRoot: string) => string;
|
|
164
175
|
}
|
|
165
176
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/eval/health.d.ts
CHANGED
|
@@ -40,7 +40,16 @@ export interface EvaluateHealthResult {
|
|
|
40
40
|
}
|
|
41
41
|
/** Absolute path to the versioned health history ledger (#2545). */
|
|
42
42
|
export declare function healthHistoryPath(projectRoot: string): string | null;
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Residual regression detector for the #1694 wipCap unsatisfiable-nudge.
|
|
45
|
+
*
|
|
46
|
+
* Pre-fix: classify treated absent `plan.policy.wipCap` as incomplete while
|
|
47
|
+
* omit-by-design (#1186 D1) made materializing the default a self-check trap.
|
|
48
|
+
* The fix records decision-provenance out-of-band (`x-directive/onboarding`),
|
|
49
|
+
* so greenfield "missing wipCap decision" is satisfiable without materializing
|
|
50
|
+
* the value field. This detector now only fires if a decision marker is set
|
|
51
|
+
* but classify still lists wipCap as missing (classifier regression).
|
|
52
|
+
*/
|
|
44
53
|
export declare function detectWipCapUnsatisfiableNudge(projectRoot: string): ContradictionEvidence | null;
|
|
45
54
|
/** Run all registered contradictory-gate detectors. */
|
|
46
55
|
export declare function detectContradictoryGates(projectRoot: string): ContradictionEvidence[];
|
package/dist/eval/health.js
CHANGED
|
@@ -6,7 +6,6 @@ import { readCorePackageVersion } from "../engine-version.js";
|
|
|
6
6
|
import { containedWrite } from "../fs/contained-write.js";
|
|
7
7
|
import { resolveProjectDefinitionPath } from "../layout/resolve.js";
|
|
8
8
|
import { healthMetricsHistoryPath } from "../metrics/resolve-metrics-home.js";
|
|
9
|
-
import { readPlanPolicy } from "../policy/plan-extensions.js";
|
|
10
9
|
import { classifyOnboarding, detectPriorState } from "../triage/welcome/prior-state.js";
|
|
11
10
|
import { validateLinks } from "../validate-content/index.js";
|
|
12
11
|
import { evaluateConformance } from "../vbrief-validate/conformance.js";
|
|
@@ -106,26 +105,27 @@ function probeContentManifest(projectRoot) {
|
|
|
106
105
|
export function healthHistoryPath(projectRoot) {
|
|
107
106
|
return healthMetricsHistoryPath(projectRoot);
|
|
108
107
|
}
|
|
109
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* Residual regression detector for the #1694 wipCap unsatisfiable-nudge.
|
|
110
|
+
*
|
|
111
|
+
* Pre-fix: classify treated absent `plan.policy.wipCap` as incomplete while
|
|
112
|
+
* omit-by-design (#1186 D1) made materializing the default a self-check trap.
|
|
113
|
+
* The fix records decision-provenance out-of-band (`x-directive/onboarding`),
|
|
114
|
+
* so greenfield "missing wipCap decision" is satisfiable without materializing
|
|
115
|
+
* the value field. This detector now only fires if a decision marker is set
|
|
116
|
+
* but classify still lists wipCap as missing (classifier regression).
|
|
117
|
+
*/
|
|
110
118
|
export function detectWipCapUnsatisfiableNudge(projectRoot) {
|
|
111
119
|
const loaded = loadPlan(projectRoot);
|
|
112
120
|
if (loaded === null) {
|
|
113
121
|
return null;
|
|
114
122
|
}
|
|
115
|
-
const { plan, filepath } = loaded;
|
|
116
|
-
const policy = readPlanPolicy(plan);
|
|
117
|
-
const wipCapPresent = typeof policy === "object" &&
|
|
118
|
-
policy !== null &&
|
|
119
|
-
!Array.isArray(policy) &&
|
|
120
|
-
"wipCap" in policy;
|
|
121
|
-
if (wipCapPresent) {
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
123
|
const state = detectPriorState(projectRoot);
|
|
125
124
|
const [, missing] = classifyOnboarding(state);
|
|
126
|
-
if (!missing.includes("wipCap")) {
|
|
125
|
+
if (!(state.wipCapDecided && missing.includes("wipCap"))) {
|
|
127
126
|
return null;
|
|
128
127
|
}
|
|
128
|
+
const { plan, filepath } = loaded;
|
|
129
129
|
const validatorErrors = validateWipCapOnPlan(plan, filepath);
|
|
130
130
|
if (validatorErrors.length > 0) {
|
|
131
131
|
return null;
|
|
@@ -133,11 +133,11 @@ export function detectWipCapUnsatisfiableNudge(projectRoot) {
|
|
|
133
133
|
return {
|
|
134
134
|
id: "wipCap-unsatisfiable-nudge",
|
|
135
135
|
kind: "unsatisfiable-nudge",
|
|
136
|
-
summary: "
|
|
136
|
+
summary: "wipCap decision marker is set but classifyOnboarding still lists wipCap as missing (#1694 regression).",
|
|
137
137
|
signals: [
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
138
|
+
"x-directive/onboarding.wipCapDecided: true",
|
|
139
|
+
"classifyOnboarding: wipCap still in missing onboarding signals",
|
|
140
|
+
"decision-provenance and completeness classifier are out of sync",
|
|
141
141
|
],
|
|
142
142
|
};
|
|
143
143
|
}
|
package/dist/hooks/dispatcher.js
CHANGED
|
@@ -7,9 +7,10 @@ import { detectNoDeftDirective, NO_DEFT_DIRECTIVE_DISABLED_MESSAGE, NO_DEFT_DIRE
|
|
|
7
7
|
import { classifyMcpTool, DEFAULT_RUNTIME_AUTHORITY_POLICY, evaluateRuntimeAuthorityDirectWrite, evaluateRuntimeAuthorityShellOp, listShellOps, loadRuntimeAuthorityFromProject, } from "../policy/runtime-authority.js";
|
|
8
8
|
import { loadStoryWriteFenceFromPath, resolveWriteFence } from "../policy/write-fence.js";
|
|
9
9
|
import { detectBranch } from "../session/git.js";
|
|
10
|
+
import { emitSessionRitualBlockedProcessCost } from "../session/process-cost.js";
|
|
10
11
|
import { markRitualStaleAfterCompact } from "../session/ritual-sentinel.js";
|
|
11
12
|
import { runSessionStartHookWrite } from "../session/session-start-hook.js";
|
|
12
|
-
import { inspectSessionRitual } from "../session/verify-session-ritual.js";
|
|
13
|
+
import { formatRitualRecoveryInstruction, inspectSessionRitual, } from "../session/verify-session-ritual.js";
|
|
13
14
|
import { hookMcpArgsText, hookShellCommand, hookToolName, hookWriteTargetPath, missingToolNameMessage, record, } from "./classify/index.js";
|
|
14
15
|
import { isExploreSpawn, isReadOnlyHookContext } from "./readonly.js";
|
|
15
16
|
import { inspectActiveScope } from "./scope.js";
|
|
@@ -452,13 +453,27 @@ function inspectMutationGates(input, toolName, seams, options) {
|
|
|
452
453
|
((root) => inspectSessionRitual(root, { tier: "gated", posture: "mutation" })))(projectRoot);
|
|
453
454
|
}
|
|
454
455
|
catch (cause) {
|
|
456
|
+
// #2994: best-effort local process-cost; never changes deny verdict.
|
|
457
|
+
emitSessionRitualBlockedProcessCost({
|
|
458
|
+
toolName,
|
|
459
|
+
code: "ritual-not-ready",
|
|
460
|
+
recoveryTier: "cold",
|
|
461
|
+
detail: `inspect threw: ${String(cause)}`,
|
|
462
|
+
}, { projectRoot });
|
|
455
463
|
return deny(input, "ritual-not-ready", toolName, `Directive could not inspect the gated session ritual: ${String(cause)}. ` +
|
|
456
|
-
"
|
|
464
|
+
formatRitualRecoveryInstruction("cold"));
|
|
457
465
|
}
|
|
458
466
|
if (ritual.code !== 0) {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
467
|
+
// #2992: prefer re-arm recovery when age/compact stale; cold when bind invalid.
|
|
468
|
+
const recoveryTier = ritual.recoveryTier === "rearm" ? "rearm" : "cold";
|
|
469
|
+
// #2994: best-effort local process-cost; never changes deny verdict.
|
|
470
|
+
emitSessionRitualBlockedProcessCost({
|
|
471
|
+
toolName,
|
|
472
|
+
code: "ritual-not-ready",
|
|
473
|
+
recoveryTier,
|
|
474
|
+
detail: ritual.message,
|
|
475
|
+
}, { projectRoot });
|
|
476
|
+
return deny(input, "ritual-not-ready", toolName, `Directive denied ${toolName}: ${ritual.message} ${formatRitualRecoveryInstruction(recoveryTier)}`);
|
|
462
477
|
}
|
|
463
478
|
if (options.proposedLifecycleExempt) {
|
|
464
479
|
const writeTarget = hookWriteTargetPath(input.payload);
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export * as session from "./session/index.js";
|
|
|
53
53
|
export * as slice from "./slice/index.js";
|
|
54
54
|
export * as storyReady from "./story-ready/index.js";
|
|
55
55
|
export * as swarm from "./swarm/index.js";
|
|
56
|
+
export * as toolEvents from "./tool-events/index.js";
|
|
56
57
|
export * as triage from "./triage/index.js";
|
|
57
58
|
export * as userConfig from "./user-config/index.js";
|
|
58
59
|
export * as validateContent from "./validate-content/index.js";
|
package/dist/index.js
CHANGED
|
@@ -54,6 +54,7 @@ export * as session from "./session/index.js";
|
|
|
54
54
|
export * as slice from "./slice/index.js";
|
|
55
55
|
export * as storyReady from "./story-ready/index.js";
|
|
56
56
|
export * as swarm from "./swarm/index.js";
|
|
57
|
+
export * as toolEvents from "./tool-events/index.js";
|
|
57
58
|
export * as triage from "./triage/index.js";
|
|
58
59
|
export * as userConfig from "./user-config/index.js";
|
|
59
60
|
export * as validateContent from "./validate-content/index.js";
|
|
@@ -45,6 +45,9 @@ export function installerManagedMatchers() {
|
|
|
45
45
|
// `deft update` framework-deposit PR trips no-mixed-core-and-app (#2277).
|
|
46
46
|
{ exact: "xbrief/.deft-version" },
|
|
47
47
|
{ exact: "xbrief/xbrief.md" },
|
|
48
|
+
// Minimal render-ready seed from init (#3013); operator may later edit identity.
|
|
49
|
+
{ exact: "xbrief/PROJECT-DEFINITION.xbrief.json" },
|
|
50
|
+
{ exact: "vbrief/PROJECT-DEFINITION.vbrief.json" },
|
|
48
51
|
{ prefix: "xbrief/schemas/" },
|
|
49
52
|
{ prefix: "xbrief/migration/" },
|
|
50
53
|
...VBRIEF_LIFECYCLE_DIRS.map((sub) => ({ exact: `xbrief/${sub}/.gitkeep` })),
|
|
@@ -34,6 +34,11 @@ export declare function userConfigDir(): string;
|
|
|
34
34
|
export declare function createUserConfigDir(io: InitDepositIo): string;
|
|
35
35
|
export declare function buildInstallSummaryJson(result: InitDepositResult, options: InitDepositArgs): Record<string, unknown>;
|
|
36
36
|
export declare function printNextSteps(result: InitDepositResult, io: InitDepositIo): void;
|
|
37
|
+
/**
|
|
38
|
+
* Ensure a minimal render-ready PROJECT-DEFINITION exists after lifecycle dirs
|
|
39
|
+
* are deposited (#3013 / epic #3009). Idempotent: never overwrites existing identity.
|
|
40
|
+
*/
|
|
41
|
+
export declare function seedMinimalProjectDefinition(projectDir: string, io: InitDepositIo): boolean;
|
|
37
42
|
export declare function runInitDeposit(args: InitDepositArgs, io: InitDepositIo, seams?: InitDepositSeams): Promise<InitDepositResult>;
|
|
38
43
|
export interface RunInitDepositCliOptions extends InitDepositArgs {
|
|
39
44
|
readonly writeOut: (text: string) => void;
|
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { existsSync, mkdirSync, readFileSync } from "node:fs";
|
|
9
9
|
import { homedir, platform } from "node:os";
|
|
10
|
-
import { join, resolve } from "node:path";
|
|
10
|
+
import { basename, join, resolve } from "node:path";
|
|
11
11
|
import { assertDepositContained } from "../deposit/contain.js";
|
|
12
12
|
import { copyTree } from "../deposit/copy-tree.js";
|
|
13
13
|
import { prunePythonArtifactsFromDeposit } from "../deposit/python-free.js";
|
|
14
14
|
import { resolveInstalledContentRoot } from "../deposit/resolve-content.js";
|
|
15
15
|
import { readCorePackageVersion } from "../engine-version.js";
|
|
16
|
+
import { renderProjectDefinition } from "../render/project-render.js";
|
|
17
|
+
import { removeStaleMigratedFrameworkNarrative } from "../xbrief-migrate/migrate-project.js";
|
|
16
18
|
import { writeAgentHookDeposit } from "./agent-hooks.js";
|
|
17
19
|
import { ensureInitGitignoreLines, reconstituteDepositFromContent } from "./gitignore.js";
|
|
18
20
|
import { depositStagePaths, printCommitGuidance } from "./hygiene.js";
|
|
@@ -20,6 +22,7 @@ import { buildLegacyRefusalJson, buildLegacyRefusalMessage, detectLegacyLayout,
|
|
|
20
22
|
import { printMigrateNudgeIfNeeded } from "./migrate.js";
|
|
21
23
|
import { ensurePrettierIgnoreLines } from "./prettierignore.js";
|
|
22
24
|
import { CANONICAL_INSTALL_ROOT, depositNeutralization, ensureTaskfile, writeAgentsMd, writeAgentsSkills, writeConsumerGitHooks, writeConsumerVbrief, writeInstallManifest, } from "./scaffold.js";
|
|
25
|
+
import { syncBareVersionMarker } from "./xbrief-projections.js";
|
|
23
26
|
export function parseInitArgv(canonicalArgv, userArgv = []) {
|
|
24
27
|
const args = [...canonicalArgv, ...userArgv];
|
|
25
28
|
let projectDir = process.cwd();
|
|
@@ -113,10 +116,36 @@ export function printNextSteps(result, io) {
|
|
|
113
116
|
io.printf(` 1. Open your AI coding assistant in ${result.projectDir}\n`);
|
|
114
117
|
io.printf(" 2. Deft skill auto-discovery is partially implemented — if your agent doesn't\n");
|
|
115
118
|
io.printf(' start setup automatically, tell it: "Use AGENTS.md"\n');
|
|
116
|
-
io.printf(" 3. On first session, the agent will guide you through
|
|
119
|
+
io.printf(" 3. On first session, the agent will guide you through USER.md (if missing).\n");
|
|
120
|
+
io.printf(" 4. PROJECT-DEFINITION is seeded at init (#3013) — run `task project:render` once to refresh items from lifecycle folders; do not multi-turn invent project identity.\n");
|
|
117
121
|
printMigrateNudgeIfNeeded(result.projectDir, io);
|
|
118
122
|
io.printf("\n");
|
|
119
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Ensure a minimal render-ready PROJECT-DEFINITION exists after lifecycle dirs
|
|
126
|
+
* are deposited (#3013 / epic #3009). Idempotent: never overwrites existing identity.
|
|
127
|
+
*/
|
|
128
|
+
export function seedMinimalProjectDefinition(projectDir, io) {
|
|
129
|
+
const xbriefDir = join(projectDir, "xbrief");
|
|
130
|
+
const legacyDir = join(projectDir, "vbrief");
|
|
131
|
+
const root = existsSync(xbriefDir) ? xbriefDir : existsSync(legacyDir) ? legacyDir : null;
|
|
132
|
+
if (root === null) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
const isXbrief = basename(root) === "xbrief";
|
|
136
|
+
const projectDefPath = join(root, isXbrief ? "PROJECT-DEFINITION.xbrief.json" : "PROJECT-DEFINITION.vbrief.json");
|
|
137
|
+
if (existsSync(projectDefPath)) {
|
|
138
|
+
io.printf("PROJECT-DEFINITION already present — leaving identity intact (#3013).\n");
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
const [ok, message] = renderProjectDefinition(root);
|
|
142
|
+
if (ok) {
|
|
143
|
+
io.printf(`${message} (minimal seed for one-shot project:render; #3013)\n`);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
io.printf(`PROJECT-DEFINITION seed skipped: ${message}\n`);
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
120
149
|
export async function runInitDeposit(args, io, seams = {}) {
|
|
121
150
|
const projectDir = args.projectDir;
|
|
122
151
|
const deftDir = join(projectDir, CANONICAL_INSTALL_ROOT);
|
|
@@ -154,6 +183,12 @@ export async function runInitDeposit(args, io, seams = {}) {
|
|
|
154
183
|
const skillsCreated = writeAgentsSkills(projectDir, io);
|
|
155
184
|
await depositNeutralization(projectDir, io);
|
|
156
185
|
await writeConsumerVbrief(projectDir, deftDir, io);
|
|
186
|
+
seedMinimalProjectDefinition(projectDir, io);
|
|
187
|
+
// Seeding PROJECT-DEFINITION.xbrief.json makes resolveLifecycleRoot succeed.
|
|
188
|
+
// Align the same consumer derivatives update repairs (#2595 / #2806) so
|
|
189
|
+
// init + git add -A is already clean under core.autocrlf=true (#2118 / #3013).
|
|
190
|
+
syncBareVersionMarker(projectDir, version);
|
|
191
|
+
removeStaleMigratedFrameworkNarrative(projectDir);
|
|
157
192
|
writeConsumerGitHooks(projectDir, deftDir, io, seams.gitHooks);
|
|
158
193
|
writeAgentHookDeposit(projectDir, io);
|
|
159
194
|
let taskfileWired = false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CompletedProcess } from "../scm/call.js";
|
|
2
2
|
import { probeRuntimeCapabilities, type RuntimeCapabilityReport } from "./platform-capabilities.js";
|
|
3
3
|
export declare const GITHUB_AUTH_MODE_INJECTED_TOKEN = "injected-token";
|
|
4
4
|
export declare const GITHUB_AUTH_MODE_HOST_GH = "host-gh";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { pyRepr } from "../scm/py-format.js";
|
|
3
3
|
import { getPlatformCapabilities, probeRuntimeCapabilities, RUNTIME_MODE_CLOUD_HEADLESS, RUNTIME_MODE_CURSOR_NATIVE_SANDBOX, } from "./platform-capabilities.js";
|
|
4
4
|
export const GITHUB_AUTH_MODE_INJECTED_TOKEN = "injected-token";
|
|
@@ -37,9 +37,31 @@ export function inferGithubAuthMode(runtimeReport) {
|
|
|
37
37
|
}
|
|
38
38
|
return GITHUB_AUTH_MODE_HOST_GH;
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Prefer live `gh` for auth/API validation. Do not route through scm.call /
|
|
42
|
+
* BINARY_PREFERENCE (ghx-first): ghx is a cached GET proxy and rejects multi-arg
|
|
43
|
+
* `api user --jq .login` forms used here (#2275 Greptile P1 / #954).
|
|
44
|
+
*/
|
|
40
45
|
function defaultRunGh(args, environ) {
|
|
41
|
-
const
|
|
42
|
-
|
|
46
|
+
const binary = "gh";
|
|
47
|
+
try {
|
|
48
|
+
const result = spawnSync(binary, [...args], {
|
|
49
|
+
env: environ,
|
|
50
|
+
encoding: "utf8",
|
|
51
|
+
timeout: 30_000,
|
|
52
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
args: [binary, ...args],
|
|
56
|
+
returncode: result.status ?? 1,
|
|
57
|
+
stdout: typeof result.stdout === "string" ? result.stdout : "",
|
|
58
|
+
stderr: typeof result.stderr === "string" ? result.stderr : "",
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
63
|
+
return { args: [binary, ...args], returncode: 1, stdout: "", stderr: message };
|
|
64
|
+
}
|
|
43
65
|
}
|
|
44
66
|
function splitRepo(repo) {
|
|
45
67
|
const idx = repo.indexOf("/");
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { ScmStubError } from "../scm/errors.js";
|
|
4
|
+
import { requireScmReady } from "../scm/readiness.js";
|
|
3
5
|
import { issueIngestMain } from "./issue-ingest.js";
|
|
4
6
|
function parseArgs(argv) {
|
|
5
7
|
const out = {};
|
|
@@ -25,6 +27,17 @@ function parseArgs(argv) {
|
|
|
25
27
|
return out;
|
|
26
28
|
}
|
|
27
29
|
export function mainEntry(argv = process.argv.slice(2)) {
|
|
30
|
+
// #2275: fail loud when gh/auth is missing in this execution env.
|
|
31
|
+
try {
|
|
32
|
+
requireScmReady();
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
if (err instanceof ScmStubError) {
|
|
36
|
+
process.stderr.write(`error: ${err.message}\n`);
|
|
37
|
+
return 2;
|
|
38
|
+
}
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
28
41
|
return issueIngestMain(parseArgs(argv));
|
|
29
42
|
}
|
|
30
43
|
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { ScmStubError } from "../scm/errors.js";
|
|
4
|
+
import { requireScmReady } from "../scm/readiness.js";
|
|
3
5
|
import { reconcileMain } from "./reconcile-issues.js";
|
|
4
6
|
function parseArgs(argv) {
|
|
5
7
|
const out = {};
|
|
@@ -23,6 +25,17 @@ function parseArgs(argv) {
|
|
|
23
25
|
return out;
|
|
24
26
|
}
|
|
25
27
|
export function mainEntry(argv = process.argv.slice(2)) {
|
|
28
|
+
// #2275: fail loud when gh/auth is missing in this execution env.
|
|
29
|
+
try {
|
|
30
|
+
requireScmReady();
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
if (err instanceof ScmStubError) {
|
|
34
|
+
process.stderr.write(`error: ${err.message}\n`);
|
|
35
|
+
return 2;
|
|
36
|
+
}
|
|
37
|
+
throw err;
|
|
38
|
+
}
|
|
26
39
|
return reconcileMain(parseArgs(argv));
|
|
27
40
|
}
|
|
28
41
|
if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === process.argv[1]) {
|
package/dist/lifecycle/events.js
CHANGED
|
@@ -6,11 +6,13 @@ import { contentRoot } from "../content-root.js";
|
|
|
6
6
|
import { ATTRIBUTION_REQUIRED_PAYLOAD } from "../events/attribution-constants.js";
|
|
7
7
|
import { containedWrite } from "../fs/contained-write.js";
|
|
8
8
|
import { ProjectionContainmentError } from "../fs/projection-containment.js";
|
|
9
|
+
import { PROCESS_COST_REQUIRED_PAYLOAD } from "../session/process-cost-constants.js";
|
|
9
10
|
/** Default event log location (project-local). */
|
|
10
11
|
export const DEFAULT_EVENT_LOG = join(".deft-cache", "events.jsonl");
|
|
11
12
|
const BEHAVIORAL_CATEGORY = "behavioral";
|
|
12
13
|
const REQUIRED_BEHAVIORAL_PAYLOAD = {
|
|
13
14
|
...ATTRIBUTION_REQUIRED_PAYLOAD,
|
|
15
|
+
...PROCESS_COST_REQUIRED_PAYLOAD,
|
|
14
16
|
"session:interrupted": ["session_id", "reason"],
|
|
15
17
|
"session:resumed": ["session_id", "interrupted_id"],
|
|
16
18
|
"plan:approved": ["plan_ref", "approver"],
|
package/dist/lifecycle/index.js
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { parseDurationMs } from "../triage/scope/duration.js";
|
|
2
|
+
/** Lifecycle folders scanned for stats. */
|
|
3
|
+
export declare const STATS_LIFECYCLE_FOLDERS: readonly ["proposed", "pending", "active", "completed", "cancelled"];
|
|
4
|
+
export type StatsLifecycleFolder = (typeof STATS_LIFECYCLE_FOLDERS)[number];
|
|
5
|
+
/** Count semantics for WWYSYDH / process forms (stable strings for --json). */
|
|
6
|
+
export declare const LIFECYCLE_STATS_SEMANTICS: {
|
|
7
|
+
readonly promoted: string;
|
|
8
|
+
readonly activated: string;
|
|
9
|
+
readonly completed: string;
|
|
10
|
+
readonly cancelled_or_failed: string;
|
|
11
|
+
readonly still_active: "snapshot count of all xbriefs currently in active/ (not filtered by --since).";
|
|
12
|
+
readonly event_time: string;
|
|
13
|
+
readonly note: string;
|
|
14
|
+
};
|
|
15
|
+
export interface LifecycleFolderTotals {
|
|
16
|
+
readonly proposed: number;
|
|
17
|
+
readonly pending: number;
|
|
18
|
+
readonly active: number;
|
|
19
|
+
readonly completed: number;
|
|
20
|
+
readonly cancelled: number;
|
|
21
|
+
}
|
|
22
|
+
export interface LifecycleStats {
|
|
23
|
+
readonly since: string;
|
|
24
|
+
readonly since_ms: number;
|
|
25
|
+
readonly as_of: string;
|
|
26
|
+
readonly window_start: string;
|
|
27
|
+
readonly project_root: string;
|
|
28
|
+
readonly lifecycle_root: string;
|
|
29
|
+
readonly promoted: number;
|
|
30
|
+
readonly activated: number;
|
|
31
|
+
readonly completed: number;
|
|
32
|
+
readonly cancelled_or_failed: number;
|
|
33
|
+
readonly still_active: number;
|
|
34
|
+
readonly folder_totals: LifecycleFolderTotals;
|
|
35
|
+
readonly semantics: typeof LIFECYCLE_STATS_SEMANTICS;
|
|
36
|
+
}
|
|
37
|
+
export interface CollectLifecycleStatsOptions {
|
|
38
|
+
readonly projectRoot: string;
|
|
39
|
+
/** Window duration string, e.g. "7d", "24h", "1w". Default "7d". */
|
|
40
|
+
readonly since?: string;
|
|
41
|
+
/** Clock for window end (tests inject a fixed Date). */
|
|
42
|
+
readonly now?: Date;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Collect lifecycle folder stats for a project root.
|
|
46
|
+
* Offline / filesystem only.
|
|
47
|
+
*/
|
|
48
|
+
export declare function collectLifecycleStats(options: CollectLifecycleStatsOptions): LifecycleStats;
|
|
49
|
+
/** Format human-readable lifecycle stats text. */
|
|
50
|
+
export declare function formatLifecycleStatsText(stats: LifecycleStats): string;
|
|
51
|
+
/** Re-export duration parse for CLI error messaging. */
|
|
52
|
+
export { parseDurationMs };
|
|
53
|
+
//# sourceMappingURL=stats.d.ts.map
|