@jakkrichm/create-nexus-devflow 2.0.27 → 2.2.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/README.md +29 -7
- package/dist/bin/create-nexus-devflow.d.ts +5 -1
- package/dist/bin/create-nexus-devflow.js +247 -4
- package/dist/bin/create-nexus-devflow.js.map +1 -1
- package/dist/lib/branch-context.d.ts +39 -0
- package/dist/lib/branch-context.js +196 -0
- package/dist/lib/branch-context.js.map +1 -0
- package/dist/lib/code-graph.d.ts +30 -0
- package/dist/lib/code-graph.js +209 -0
- package/dist/lib/code-graph.js.map +1 -0
- package/dist/lib/context-slicer.d.ts +31 -0
- package/dist/lib/context-slicer.js +234 -0
- package/dist/lib/context-slicer.js.map +1 -0
- package/dist/lib/current-work.js +4 -2
- package/dist/lib/current-work.js.map +1 -1
- package/dist/lib/dashboard-page.d.ts +1 -1
- package/dist/lib/dashboard-page.js +140 -56
- package/dist/lib/dashboard-page.js.map +1 -1
- package/dist/lib/dashboard-snapshot.d.ts +13 -0
- package/dist/lib/dashboard-snapshot.js +24 -6
- package/dist/lib/dashboard-snapshot.js.map +1 -1
- package/dist/lib/dashboard.js +38 -0
- package/dist/lib/dashboard.js.map +1 -1
- package/dist/lib/drift-reconciler.d.ts +38 -0
- package/dist/lib/drift-reconciler.js +155 -0
- package/dist/lib/drift-reconciler.js.map +1 -0
- package/dist/lib/gatekeeper.d.ts +1 -0
- package/dist/lib/gatekeeper.js +30 -1
- package/dist/lib/gatekeeper.js.map +1 -1
- package/dist/lib/git-hooks.js +41 -16
- package/dist/lib/git-hooks.js.map +1 -1
- package/dist/lib/ide-extension.d.ts +38 -0
- package/dist/lib/ide-extension.js +61 -0
- package/dist/lib/ide-extension.js.map +1 -0
- package/dist/lib/mcp.d.ts +36 -0
- package/dist/lib/mcp.js +653 -0
- package/dist/lib/mcp.js.map +1 -0
- package/dist/lib/project-metadata.d.ts +1 -1
- package/dist/lib/project-metadata.js +3 -2
- package/dist/lib/project-metadata.js.map +1 -1
- package/dist/lib/status.d.ts +1 -1
- package/dist/lib/status.js +4 -4
- package/dist/lib/status.js.map +1 -1
- package/dist/lib/swarm-orchestrator.d.ts +31 -0
- package/dist/lib/swarm-orchestrator.js +134 -0
- package/dist/lib/swarm-orchestrator.js.map +1 -0
- package/dist/lib/update.js +7 -3
- package/dist/lib/update.js.map +1 -1
- package/dist/lib/webview-studio.d.ts +8 -0
- package/dist/lib/webview-studio.js +463 -0
- package/dist/lib/webview-studio.js.map +1 -0
- package/dist/lib/workflow-state.js +24 -8
- package/dist/lib/workflow-state.js.map +1 -1
- package/package.json +1 -1
- package/template/.agents/skills/adopt/SKILL.md +58 -5
- package/template/.agents/skills/doctor/SKILL.md +23 -16
- package/template/.agents/skills/implement/SKILL.md +2 -2
- package/template/.agents/skills/onboard/SKILL.md +18 -17
- package/template/.agents/skills/rollback/SKILL.md +1 -1
- package/template/.claude/skills/00-explore/SKILL.md +2 -2
- package/template/.claude/skills/10-define/SKILL.md +2 -2
- package/template/.claude/skills/20-spec/SKILL.md +1 -2
- package/template/.claude/skills/30-plan/SKILL.md +1 -2
- package/template/.claude/skills/40-execute/SKILL.md +2 -2
- package/template/.claude/skills/50-verify/SKILL.md +2 -2
- package/template/.claude/skills/60-report/SKILL.md +2 -2
- package/template/.claude/skills/70-deliver/SKILL.md +2 -2
- package/template/.claude/skills/adopt/SKILL.md +191 -75
- package/template/.claude/skills/audit/SKILL.md +267 -133
- package/template/.claude/skills/autopilot/SKILL.md +226 -167
- package/template/.claude/skills/brainstorm/SKILL.md +62 -0
- package/template/.claude/skills/brief/SKILL.md +93 -92
- package/template/.claude/skills/check/SKILL.md +96 -76
- package/template/.claude/skills/ci/SKILL.md +140 -61
- package/template/.claude/skills/complete/SKILL.md +156 -101
- package/template/.claude/skills/convert-any-to-md/SKILL.md +2 -2
- package/template/.claude/skills/convert-any-to-md/references/setup.md +29 -0
- package/template/.claude/skills/convert-any-to-md/scripts/convert_any_to_md.py +487 -0
- package/template/.claude/skills/convert-any-to-md/scripts/requirements.txt +3 -0
- package/template/.claude/skills/debug/SKILL.md +124 -49
- package/template/.claude/skills/devflow/SKILL.md +9 -3
- package/template/.claude/skills/discovery/SKILL.md +150 -129
- package/template/.claude/skills/doctor/SKILL.md +195 -72
- package/template/.claude/skills/feature/SKILL.md +195 -151
- package/template/.claude/skills/fix/SKILL.md +41 -90
- package/template/.claude/skills/idea/SKILL.md +2 -2
- package/template/.claude/skills/implement/SKILL.md +189 -46
- package/template/.claude/skills/onboard/SKILL.md +216 -85
- package/template/.claude/skills/overview/SKILL.md +44 -29
- package/template/.claude/skills/prototype/SKILL.md +82 -27
- package/template/.claude/skills/release/SKILL.md +119 -130
- package/template/.claude/skills/report-html/SKILL.md +2 -2
- package/template/.claude/skills/rollback/SKILL.md +123 -77
- package/template/.claude/skills/status/SKILL.md +109 -0
- package/template/.claude/skills/test/SKILL.md +2 -2
- package/template/.claude/skills/tests/SKILL.md +126 -0
- package/template/.claude/skills/try/SKILL.md +77 -65
- package/template/AGENTS.md +2 -1
- package/template/devflow/build-plan.md +50 -20
- package/template/devflow/history/features/README.md +5 -0
- package/template/devflow/history/fixes/README.md +5 -0
- package/template/devflow/history/rollbacks/README.md +5 -0
- package/template/devflow/project-plan.md +70 -18
- package/template/devflow/reference/studio.html +504 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface GitDriftReport {
|
|
2
|
+
hasDrift: boolean;
|
|
3
|
+
undocumentedFiles: string[];
|
|
4
|
+
phantomFiles: string[];
|
|
5
|
+
matchedFiles: string[];
|
|
6
|
+
gitModifiedFiles: string[];
|
|
7
|
+
specFiles: string[];
|
|
8
|
+
stageDrift: {
|
|
9
|
+
isDrifted: boolean;
|
|
10
|
+
activeBranch: string | null;
|
|
11
|
+
stageRunningId: string | null;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export interface ReconcileResult {
|
|
15
|
+
reconciled: boolean;
|
|
16
|
+
addedFiles: string[];
|
|
17
|
+
healedStage: boolean;
|
|
18
|
+
message: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes file path to forward slashes relative to workspace root.
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeRelativePath(projectRoot: string, filePath: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Parses the "Files to Modify/Create" section from a living spec markdown.
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseSpecFilesList(specContent: string): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Detects git drift between modified repository files and spec declaration.
|
|
30
|
+
*/
|
|
31
|
+
export declare function detectGitDrift(projectRoot: string, explicitBranch?: string): Promise<GitDriftReport>;
|
|
32
|
+
/**
|
|
33
|
+
* Automatically reconciles and synchronizes living spec and stage file.
|
|
34
|
+
*/
|
|
35
|
+
export declare function reconcileState(projectRoot: string, options?: {
|
|
36
|
+
autoAddUndocumented?: boolean;
|
|
37
|
+
healStage?: boolean;
|
|
38
|
+
}): Promise<ReconcileResult>;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import fsSync from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { resolveActiveContextPaths } from "./branch-context.js";
|
|
5
|
+
import { readGitStatus } from "./git-status.js";
|
|
6
|
+
const IGNORED_DRIFT_PATTERNS = [
|
|
7
|
+
/devflow\/context\/current-feature\.md$/i,
|
|
8
|
+
/devflow\/context\/current-stage\.md$/i,
|
|
9
|
+
/devflow\/history\//i,
|
|
10
|
+
/devflow\/runs\//i,
|
|
11
|
+
/devflow\/discoveries\//i,
|
|
12
|
+
/\.gitignore$/i,
|
|
13
|
+
/\.nexus\//i,
|
|
14
|
+
/\.agents\//i,
|
|
15
|
+
/\.claude\//i,
|
|
16
|
+
/node_modules\//i,
|
|
17
|
+
/dist\//i,
|
|
18
|
+
/package-lock\.json$/i
|
|
19
|
+
];
|
|
20
|
+
/**
|
|
21
|
+
* Normalizes file path to forward slashes relative to workspace root.
|
|
22
|
+
*/
|
|
23
|
+
export function normalizeRelativePath(projectRoot, filePath) {
|
|
24
|
+
const relative = path.isAbsolute(filePath)
|
|
25
|
+
? path.relative(projectRoot, filePath)
|
|
26
|
+
: filePath;
|
|
27
|
+
return relative.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses the "Files to Modify/Create" section from a living spec markdown.
|
|
31
|
+
*/
|
|
32
|
+
export function parseSpecFilesList(specContent) {
|
|
33
|
+
const files = [];
|
|
34
|
+
const lines = specContent.split("\n");
|
|
35
|
+
let inFilesSection = false;
|
|
36
|
+
for (const line of lines) {
|
|
37
|
+
const trimmed = line.trim();
|
|
38
|
+
if (/Files\s+to\s+Modify\/Create/i.test(trimmed)) {
|
|
39
|
+
inFilesSection = true;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (inFilesSection) {
|
|
43
|
+
// Exit if next major section, horizontal rule, or next main bold bullet in Plan (e.g. - **Test Decision**:)
|
|
44
|
+
if (/^##+\s+/.test(trimmed) || /^-\s+\*\*[^*]+\*\*:/i.test(trimmed) || trimmed.startsWith("---")) {
|
|
45
|
+
inFilesSection = false;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (trimmed.startsWith("-") || trimmed.startsWith("*")) {
|
|
49
|
+
// Extract backtick path `path/to/file.ext` or direct path
|
|
50
|
+
const match = trimmed.match(/`([^`]+)`/) || trimmed.match(/^[*-]\s+(?:\[[ x]\]\s+)?([a-zA-Z0-9_./\\-]+\.[a-zA-Z0-9]+)/);
|
|
51
|
+
if (match && match[1]) {
|
|
52
|
+
const clean = match[1].trim().replace(/\\/g, "/");
|
|
53
|
+
// Ensure it looks like a valid file path with extension
|
|
54
|
+
if (/\.[a-zA-Z0-9_-]+$/.test(clean) && !clean.startsWith("http")) {
|
|
55
|
+
files.push(clean);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return Array.from(new Set(files));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Detects git drift between modified repository files and spec declaration.
|
|
65
|
+
*/
|
|
66
|
+
export async function detectGitDrift(projectRoot, explicitBranch) {
|
|
67
|
+
const contextPaths = await resolveActiveContextPaths(projectRoot, explicitBranch);
|
|
68
|
+
const gitStatus = await readGitStatus(projectRoot);
|
|
69
|
+
let specFiles = [];
|
|
70
|
+
let stageRunningId = null;
|
|
71
|
+
if (fsSync.existsSync(contextPaths.featureSpecPath)) {
|
|
72
|
+
const specContent = await fs.readFile(contextPaths.featureSpecPath, "utf8");
|
|
73
|
+
specFiles = parseSpecFilesList(specContent);
|
|
74
|
+
}
|
|
75
|
+
if (fsSync.existsSync(contextPaths.stagePath)) {
|
|
76
|
+
const stageContent = await fs.readFile(contextPaths.stagePath, "utf8");
|
|
77
|
+
const match = stageContent.match(/Active Running ID:\s*`?([a-zA-Z0-9_-]+)`?/i);
|
|
78
|
+
if (match)
|
|
79
|
+
stageRunningId = match[1];
|
|
80
|
+
}
|
|
81
|
+
// Collect git changed files
|
|
82
|
+
const rawGitFiles = [];
|
|
83
|
+
if (gitStatus.available) {
|
|
84
|
+
if (gitStatus.changedFiles && Array.isArray(gitStatus.changedFiles)) {
|
|
85
|
+
rawGitFiles.push(...gitStatus.changedFiles);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Filter out ignored/transient files
|
|
89
|
+
const gitModifiedFiles = rawGitFiles
|
|
90
|
+
.map((f) => normalizeRelativePath(projectRoot, f))
|
|
91
|
+
.filter((f) => !IGNORED_DRIFT_PATTERNS.some((p) => p.test(f)));
|
|
92
|
+
const normalizedSpecFiles = specFiles.map((f) => normalizeRelativePath(projectRoot, f));
|
|
93
|
+
const undocumentedFiles = gitModifiedFiles.filter((gf) => !normalizedSpecFiles.some((sf) => sf === gf || gf.endsWith(sf) || sf.endsWith(gf)));
|
|
94
|
+
const phantomFiles = normalizedSpecFiles.filter((sf) => !gitModifiedFiles.some((gf) => gf === sf || gf.endsWith(sf) || sf.endsWith(gf)));
|
|
95
|
+
const matchedFiles = gitModifiedFiles.filter((gf) => normalizedSpecFiles.some((sf) => sf === gf || gf.endsWith(sf) || sf.endsWith(gf)));
|
|
96
|
+
const isStageDrifted = Boolean(gitStatus.branch &&
|
|
97
|
+
stageRunningId &&
|
|
98
|
+
stageRunningId !== "None" &&
|
|
99
|
+
!gitStatus.branch.includes(stageRunningId) &&
|
|
100
|
+
!stageRunningId.includes(gitStatus.branch));
|
|
101
|
+
const hasDrift = undocumentedFiles.length > 0 || isStageDrifted;
|
|
102
|
+
return {
|
|
103
|
+
hasDrift,
|
|
104
|
+
undocumentedFiles,
|
|
105
|
+
phantomFiles,
|
|
106
|
+
matchedFiles,
|
|
107
|
+
gitModifiedFiles,
|
|
108
|
+
specFiles: normalizedSpecFiles,
|
|
109
|
+
stageDrift: {
|
|
110
|
+
isDrifted: isStageDrifted,
|
|
111
|
+
activeBranch: gitStatus.branch || null,
|
|
112
|
+
stageRunningId
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Automatically reconciles and synchronizes living spec and stage file.
|
|
118
|
+
*/
|
|
119
|
+
export async function reconcileState(projectRoot, options = { autoAddUndocumented: true, healStage: true }) {
|
|
120
|
+
const drift = await detectGitDrift(projectRoot);
|
|
121
|
+
const contextPaths = await resolveActiveContextPaths(projectRoot);
|
|
122
|
+
const addedFiles = [];
|
|
123
|
+
let healedStage = false;
|
|
124
|
+
// 1. Reconcile Undocumented Files into current-feature.md
|
|
125
|
+
if (options.autoAddUndocumented && drift.undocumentedFiles.length > 0 && fsSync.existsSync(contextPaths.featureSpecPath)) {
|
|
126
|
+
const specContent = await fs.readFile(contextPaths.featureSpecPath, "utf8");
|
|
127
|
+
const lines = specContent.split("\n");
|
|
128
|
+
const targetIdx = lines.findIndex((l) => /Files\s+to\s+Modify\/Create/i.test(l));
|
|
129
|
+
if (targetIdx !== -1) {
|
|
130
|
+
const newEntries = drift.undocumentedFiles.map((f) => ` - \`${f}\` (Auto-reconciled from Git changes)`);
|
|
131
|
+
lines.splice(targetIdx + 1, 0, ...newEntries);
|
|
132
|
+
await fs.writeFile(contextPaths.featureSpecPath, lines.join("\n"), "utf8");
|
|
133
|
+
addedFiles.push(...drift.undocumentedFiles);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// 2. Heal current-stage.md if drifted
|
|
137
|
+
if (options.healStage && drift.stageDrift.isDrifted && drift.stageDrift.activeBranch && fsSync.existsSync(contextPaths.stagePath)) {
|
|
138
|
+
const stageContent = await fs.readFile(contextPaths.stagePath, "utf8");
|
|
139
|
+
const cleanBranch = drift.stageDrift.activeBranch.replace(/^(feature|fix|chore)\//, "");
|
|
140
|
+
const updatedStage = stageContent.replace(/Active Running ID:\s*`?[^`\n]+`?/i, `Active Running ID: \`${cleanBranch}\``);
|
|
141
|
+
await fs.writeFile(contextPaths.stagePath, updatedStage, "utf8");
|
|
142
|
+
healedStage = true;
|
|
143
|
+
}
|
|
144
|
+
const reconciled = addedFiles.length > 0 || healedStage;
|
|
145
|
+
const message = reconciled
|
|
146
|
+
? `Reconciliation complete: Added ${addedFiles.length} undocumented file(s) to spec, stage healed: ${healedStage}`
|
|
147
|
+
: "No drift detected or nothing to reconcile.";
|
|
148
|
+
return {
|
|
149
|
+
reconciled,
|
|
150
|
+
addedFiles,
|
|
151
|
+
healedStage,
|
|
152
|
+
message
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=drift-reconciler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift-reconciler.js","sourceRoot":"","sources":["../../lib/drift-reconciler.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/gatekeeper.d.ts
CHANGED
package/dist/lib/gatekeeper.js
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { readProjectStatus } from "./status.js";
|
|
2
|
+
import { detectGitDrift } from "./drift-reconciler.js";
|
|
2
3
|
import { createStyle } from "./ui.js";
|
|
3
4
|
export async function evaluateGate(projectRoot, options = {}) {
|
|
4
5
|
const status = await readProjectStatus(projectRoot);
|
|
5
6
|
const violations = [];
|
|
7
|
+
const warnings = [];
|
|
6
8
|
// Check 1: Active Findings Blockers (P0 / P1 in open or fixed status)
|
|
7
|
-
const blockers = status.findings.blockers;
|
|
9
|
+
const blockers = status.findings.blockers || [];
|
|
8
10
|
for (const blocker of blockers) {
|
|
9
11
|
violations.push(`Finding ${blocker.id} [${blocker.severity}] (${blocker.status}): ${blocker.title}`);
|
|
10
12
|
}
|
|
13
|
+
// Check 1.1: Non-blocker findings warnings (P2 / P3 in open status)
|
|
14
|
+
const nonBlockers = (status.findings.active || []).filter((item) => (item.severity === "P2" || item.severity === "P3") && (item.status === "open" || item.status === "unverified"));
|
|
15
|
+
for (const item of nonBlockers) {
|
|
16
|
+
warnings.push(`Advisory Finding ${item.id} [${item.severity}] (${item.status}): ${item.title}`);
|
|
17
|
+
}
|
|
18
|
+
// Check 1.2: Status / findings warnings
|
|
19
|
+
for (const w of status.warnings || []) {
|
|
20
|
+
warnings.push(`Warning (${w.code}): ${w.message}`);
|
|
21
|
+
}
|
|
11
22
|
// Check 2: Uncompleted tasks in Living Spec
|
|
12
23
|
const remaining = status.currentWork.remaining;
|
|
13
24
|
if (status.currentWork.state === "active" && remaining > 0) {
|
|
@@ -19,6 +30,14 @@ export async function evaluateGate(projectRoot, options = {}) {
|
|
|
19
30
|
violations.push(`Living spec '${status.currentWork.runId || "active"}' is unverified (run /check before delivery)`);
|
|
20
31
|
}
|
|
21
32
|
}
|
|
33
|
+
// Check 4: Git drift advisory check
|
|
34
|
+
try {
|
|
35
|
+
const drift = await detectGitDrift(projectRoot);
|
|
36
|
+
if (drift.hasDrift && drift.undocumentedFiles.length > 0) {
|
|
37
|
+
warnings.push(`Warning (git_drift): ${drift.undocumentedFiles.length} file(s) modified in git without being listed in living spec.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch { }
|
|
22
41
|
const passed = violations.length === 0;
|
|
23
42
|
const exitCode = passed ? 0 : 1;
|
|
24
43
|
let summary = "";
|
|
@@ -37,6 +56,7 @@ export async function evaluateGate(projectRoot, options = {}) {
|
|
|
37
56
|
strict: options.strict === true,
|
|
38
57
|
completionState: status.completion.state,
|
|
39
58
|
violations,
|
|
59
|
+
warnings,
|
|
40
60
|
findingsBlockers: blockers.length,
|
|
41
61
|
remainingTasks: remaining,
|
|
42
62
|
summary
|
|
@@ -58,6 +78,15 @@ export function formatGateReport(report, options = {}) {
|
|
|
58
78
|
lines.push(` - ${style.red("✖")} ${v}`);
|
|
59
79
|
}
|
|
60
80
|
lines.push("");
|
|
81
|
+
}
|
|
82
|
+
if (report.warnings.length > 0) {
|
|
83
|
+
lines.push(style.bold(style.yellow("Warnings / Advisories:")));
|
|
84
|
+
for (const w of report.warnings) {
|
|
85
|
+
lines.push(` - ${style.yellow("⚠")} ${style.dim(w)}`);
|
|
86
|
+
}
|
|
87
|
+
lines.push("");
|
|
88
|
+
}
|
|
89
|
+
if (report.violations.length > 0) {
|
|
61
90
|
lines.push(style.yellow("Suggested Actions:"));
|
|
62
91
|
if (report.findingsBlockers > 0) {
|
|
63
92
|
lines.push(` - Resolve blockers: ${style.bold("nexus-devflow findings --blockers")}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gatekeeper.js","sourceRoot":"","sources":["../../lib/gatekeeper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"gatekeeper.js","sourceRoot":"","sources":["../../lib/gatekeeper.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/git-hooks.js
CHANGED
|
@@ -6,38 +6,57 @@ function createHookScript(strict = true) {
|
|
|
6
6
|
return `#!/bin/sh
|
|
7
7
|
${HOOK_MARKER}
|
|
8
8
|
echo "[Nexus-DevFlow] Verifying Quality Gatekeeper before proceeding..."
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
if command -v npx >/dev/null 2>&1; then
|
|
11
|
+
npx nexus-devflow check-gate${strictFlag}
|
|
12
|
+
else
|
|
13
|
+
echo "[Nexus-DevFlow] Warning: 'npx' not found in PATH, skipping local gatekeeper check."
|
|
14
|
+
exit 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
10
17
|
EXIT_CODE=$?
|
|
11
18
|
if [ $EXIT_CODE -ne 0 ]; then
|
|
12
19
|
echo ""
|
|
13
20
|
echo "[Nexus-DevFlow] Action aborted: Quality Gatekeeper failed."
|
|
14
|
-
echo "[Nexus-DevFlow] Fix blockers or resolve findings before proceeding."
|
|
21
|
+
echo "[Nexus-DevFlow] Fix blockers, complete tasks, or resolve findings before proceeding."
|
|
15
22
|
exit 1
|
|
16
23
|
fi
|
|
17
24
|
`;
|
|
18
25
|
}
|
|
19
|
-
|
|
20
|
-
const
|
|
26
|
+
async function resolveGitHooksDir(projectRoot) {
|
|
27
|
+
const gitPath = path.join(projectRoot, ".git");
|
|
21
28
|
try {
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
const stats = await fs.lstat(gitPath);
|
|
30
|
+
if (stats.isDirectory()) {
|
|
31
|
+
return path.join(gitPath, "hooks");
|
|
32
|
+
}
|
|
33
|
+
if (stats.isFile()) {
|
|
34
|
+
const content = await fs.readFile(gitPath, "utf8");
|
|
35
|
+
const match = content.match(/^gitdir:\s*(.+)$/m);
|
|
36
|
+
if (match) {
|
|
37
|
+
const rawGitDir = match[1].trim();
|
|
38
|
+
const gitDir = path.isAbsolute(rawGitDir)
|
|
39
|
+
? rawGitDir
|
|
40
|
+
: path.resolve(projectRoot, rawGitDir);
|
|
41
|
+
return path.join(gitDir, "hooks");
|
|
42
|
+
}
|
|
30
43
|
}
|
|
31
44
|
}
|
|
32
45
|
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
export async function installGitHook(projectRoot, hookType = "pre-commit", options = {}) {
|
|
51
|
+
const hooksDir = await resolveGitHooksDir(projectRoot);
|
|
52
|
+
if (!hooksDir) {
|
|
33
53
|
return {
|
|
34
54
|
success: false,
|
|
35
55
|
hookType,
|
|
36
56
|
path: "",
|
|
37
|
-
message: "Target directory is not a Git repository (.git directory not found)."
|
|
57
|
+
message: "Target directory is not a Git repository (.git directory or worktree not found)."
|
|
38
58
|
};
|
|
39
59
|
}
|
|
40
|
-
const hooksDir = path.join(gitDir, "hooks");
|
|
41
60
|
await fs.mkdir(hooksDir, { recursive: true });
|
|
42
61
|
const hookPath = path.join(hooksDir, hookType);
|
|
43
62
|
const scriptContent = createHookScript(options.strict !== false);
|
|
@@ -50,8 +69,14 @@ export async function installGitHook(projectRoot, hookType = "pre-commit", optio
|
|
|
50
69
|
};
|
|
51
70
|
}
|
|
52
71
|
export async function uninstallGitHooks(projectRoot) {
|
|
53
|
-
const
|
|
54
|
-
|
|
72
|
+
const hooksDir = await resolveGitHooksDir(projectRoot);
|
|
73
|
+
if (!hooksDir) {
|
|
74
|
+
return {
|
|
75
|
+
success: true,
|
|
76
|
+
removed: [],
|
|
77
|
+
message: "Target directory is not a Git repository (.git directory or worktree not found)."
|
|
78
|
+
};
|
|
79
|
+
}
|
|
55
80
|
const removed = [];
|
|
56
81
|
const types = ["pre-commit", "pre-push"];
|
|
57
82
|
for (const t of types) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-hooks.js","sourceRoot":"","sources":["../../lib/git-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAiB7B,MAAM,WAAW,GAAG,6CAA6C,CAAC;AAElE,SAAS,gBAAgB,CAAC,SAAkB,IAAI;IAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7C,OAAO;EACP,WAAW
|
|
1
|
+
{"version":3,"file":"git-hooks.js","sourceRoot":"","sources":["../../lib/git-hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface IdeExtensionManifest {
|
|
2
|
+
name: string;
|
|
3
|
+
displayName: string;
|
|
4
|
+
description: string;
|
|
5
|
+
version: string;
|
|
6
|
+
publisher: string;
|
|
7
|
+
engines: {
|
|
8
|
+
vscode: string;
|
|
9
|
+
};
|
|
10
|
+
categories: string[];
|
|
11
|
+
activationEvents: string[];
|
|
12
|
+
main: string;
|
|
13
|
+
contributes: {
|
|
14
|
+
viewsContainers: {
|
|
15
|
+
activitybar: Array<{
|
|
16
|
+
id: string;
|
|
17
|
+
title: string;
|
|
18
|
+
icon: string;
|
|
19
|
+
}>;
|
|
20
|
+
};
|
|
21
|
+
views: {
|
|
22
|
+
[containerId: string]: Array<{
|
|
23
|
+
type: string;
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
}>;
|
|
27
|
+
};
|
|
28
|
+
commands: Array<{
|
|
29
|
+
command: string;
|
|
30
|
+
title: string;
|
|
31
|
+
category: string;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generates the official VS Code / Antigravity IDE Extension package.json manifest.
|
|
37
|
+
*/
|
|
38
|
+
export declare function generateIdeExtensionManifest(): IdeExtensionManifest;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates the official VS Code / Antigravity IDE Extension package.json manifest.
|
|
3
|
+
*/
|
|
4
|
+
export function generateIdeExtensionManifest() {
|
|
5
|
+
return {
|
|
6
|
+
name: "nexus-devflow-studio",
|
|
7
|
+
displayName: "Nexus-DevFlow Studio",
|
|
8
|
+
description: "Interactive 3-Pillars Kanban Dashboard, Dynamic Spec Manager & Quality Gatekeeper for Nexus-DevFlow",
|
|
9
|
+
version: "2.0.27",
|
|
10
|
+
publisher: "jakkrichm",
|
|
11
|
+
engines: {
|
|
12
|
+
vscode: "^1.80.0"
|
|
13
|
+
},
|
|
14
|
+
categories: ["Programming Languages", "Other", "Linters"],
|
|
15
|
+
activationEvents: ["onView:nexusDevFlowStudioView", "onCommand:nexusDevFlow.openStudio"],
|
|
16
|
+
main: "./out/extension.js",
|
|
17
|
+
contributes: {
|
|
18
|
+
viewsContainers: {
|
|
19
|
+
activitybar: [
|
|
20
|
+
{
|
|
21
|
+
id: "nexus-devflow-container",
|
|
22
|
+
title: "Nexus-DevFlow",
|
|
23
|
+
icon: "resources/devflow-icon.svg"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
views: {
|
|
28
|
+
"nexus-devflow-container": [
|
|
29
|
+
{
|
|
30
|
+
type: "webview",
|
|
31
|
+
id: "nexusDevFlowStudioView",
|
|
32
|
+
name: "DevFlow Studio"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
commands: [
|
|
37
|
+
{
|
|
38
|
+
command: "nexusDevFlow.openStudio",
|
|
39
|
+
title: "Open DevFlow Studio Webview",
|
|
40
|
+
category: "Nexus-DevFlow"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
command: "nexusDevFlow.checkGate",
|
|
44
|
+
title: "Run Quality Gatekeeper Check",
|
|
45
|
+
category: "Nexus-DevFlow"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
command: "nexusDevFlow.detectDrift",
|
|
49
|
+
title: "Detect Git Diff Drift",
|
|
50
|
+
category: "Nexus-DevFlow"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
command: "nexusDevFlow.reconcileState",
|
|
54
|
+
title: "Auto-Heal & Reconcile State",
|
|
55
|
+
category: "Nexus-DevFlow"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=ide-extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ide-extension.js","sourceRoot":"","sources":["../../lib/ide-extension.ts"],"names":[],"mappings":"AAmCA;;GAEG;AACH,MAAM,UAAU,4BAA4B;IAC1C,OAAO;QACL,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,sBAAsB;QACnC,WAAW,EAAE,qGAAqG;QAClH,OAAO,EAAE,QAAQ;QACjB,SAAS,EAAE,WAAW;QACtB,OAAO,EAAE;YACP,MAAM,EAAE,SAAS;SAClB;QACD,UAAU,EAAE,CAAC,uBAAuB,EAAE,OAAO,EAAE,SAAS,CAAC;QACzD,gBAAgB,EAAE,CAAC,+BAA+B,EAAE,mCAAmC,CAAC;QACxF,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EAAE;YACX,eAAe,EAAE;gBACf,WAAW,EAAE;oBACX;wBACE,EAAE,EAAE,yBAAyB;wBAC7B,KAAK,EAAE,eAAe;wBACtB,IAAI,EAAE,4BAA4B;qBACnC;iBACF;aACF;YACD,KAAK,EAAE;gBACL,yBAAyB,EAAE;oBACzB;wBACE,IAAI,EAAE,SAAS;wBACf,EAAE,EAAE,wBAAwB;wBAC5B,IAAI,EAAE,gBAAgB;qBACvB;iBACF;aACF;YACD,QAAQ,EAAE;gBACR;oBACE,OAAO,EAAE,yBAAyB;oBAClC,KAAK,EAAE,6BAA6B;oBACpC,QAAQ,EAAE,eAAe;iBAC1B;gBACD;oBACE,OAAO,EAAE,wBAAwB;oBACjC,KAAK,EAAE,8BAA8B;oBACrC,QAAQ,EAAE,eAAe;iBAC1B;gBACD;oBACE,OAAO,EAAE,0BAA0B;oBACnC,KAAK,EAAE,uBAAuB;oBAC9B,QAAQ,EAAE,eAAe;iBAC1B;gBACD;oBACE,OAAO,EAAE,6BAA6B;oBACtC,KAAK,EAAE,6BAA6B;oBACpC,QAAQ,EAAE,eAAe;iBAC1B;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Readable, Writable } from "node:stream";
|
|
2
|
+
export interface JsonRpcRequest {
|
|
3
|
+
jsonrpc: "2.0";
|
|
4
|
+
id?: string | number | null;
|
|
5
|
+
method: string;
|
|
6
|
+
params?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export interface JsonRpcResponse {
|
|
9
|
+
jsonrpc: "2.0";
|
|
10
|
+
id: string | number | null;
|
|
11
|
+
result?: unknown;
|
|
12
|
+
error?: {
|
|
13
|
+
code: number;
|
|
14
|
+
message: string;
|
|
15
|
+
data?: unknown;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export interface McpToolDefinition {
|
|
19
|
+
name: string;
|
|
20
|
+
description: string;
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: "object";
|
|
23
|
+
properties: Record<string, unknown>;
|
|
24
|
+
required?: string[];
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare const DEVFLOW_MCP_TOOLS: McpToolDefinition[];
|
|
28
|
+
export declare function handleToolCall(projectRoot: string, name: string, args?: Record<string, unknown>): Promise<{
|
|
29
|
+
content: Array<{
|
|
30
|
+
type: "text";
|
|
31
|
+
text: string;
|
|
32
|
+
}>;
|
|
33
|
+
isError?: boolean;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function processMcpMessage(projectRoot: string, rawMessage: string): Promise<JsonRpcResponse | null>;
|
|
36
|
+
export declare function startMcpServer(projectRoot: string, inStream?: Readable, outStream?: Writable): void;
|