@evref-bl/dev-nexus 0.1.0-alpha.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 +677 -0
- package/dist/browserOpener.d.ts +9 -0
- package/dist/browserOpener.js +47 -0
- package/dist/cli.d.ts +18 -0
- package/dist/cli.js +2374 -0
- package/dist/gitWorktreeService.d.ts +57 -0
- package/dist/gitWorktreeService.js +157 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +47 -0
- package/dist/nexusAgentMcpConfig.d.ts +30 -0
- package/dist/nexusAgentMcpConfig.js +228 -0
- package/dist/nexusAutomation.d.ts +103 -0
- package/dist/nexusAutomation.js +390 -0
- package/dist/nexusAutomationAgentLaunch.d.ts +148 -0
- package/dist/nexusAutomationAgentLaunch.js +855 -0
- package/dist/nexusAutomationAgentProfile.d.ts +39 -0
- package/dist/nexusAutomationAgentProfile.js +103 -0
- package/dist/nexusAutomationAgentSurface.d.ts +62 -0
- package/dist/nexusAutomationAgentSurface.js +90 -0
- package/dist/nexusAutomationCommandExecutor.d.ts +29 -0
- package/dist/nexusAutomationCommandExecutor.js +251 -0
- package/dist/nexusAutomationConfig.d.ts +114 -0
- package/dist/nexusAutomationConfig.js +547 -0
- package/dist/nexusAutomationEnqueue.d.ts +37 -0
- package/dist/nexusAutomationEnqueue.js +128 -0
- package/dist/nexusAutomationRunOnce.d.ts +91 -0
- package/dist/nexusAutomationRunOnce.js +586 -0
- package/dist/nexusAutomationScheduler.d.ts +50 -0
- package/dist/nexusAutomationScheduler.js +196 -0
- package/dist/nexusAutomationStatus.d.ts +55 -0
- package/dist/nexusAutomationStatus.js +462 -0
- package/dist/nexusAutomationTarget.d.ts +19 -0
- package/dist/nexusAutomationTarget.js +33 -0
- package/dist/nexusAutomationTargetCycle.d.ts +90 -0
- package/dist/nexusAutomationTargetCycle.js +282 -0
- package/dist/nexusAutomationTargetReport.d.ts +136 -0
- package/dist/nexusAutomationTargetReport.js +504 -0
- package/dist/nexusAutomationWorktreeSetup.d.ts +89 -0
- package/dist/nexusAutomationWorktreeSetup.js +661 -0
- package/dist/nexusCoordination.d.ts +198 -0
- package/dist/nexusCoordination.js +1018 -0
- package/dist/nexusExtension.d.ts +31 -0
- package/dist/nexusExtension.js +1 -0
- package/dist/nexusHomeConfig.d.ts +38 -0
- package/dist/nexusHomeConfig.js +133 -0
- package/dist/nexusMcpServer.d.ts +31 -0
- package/dist/nexusMcpServer.js +1036 -0
- package/dist/nexusPluginCapabilities.d.ts +197 -0
- package/dist/nexusPluginCapabilities.js +201 -0
- package/dist/nexusProjectConfig.d.ts +95 -0
- package/dist/nexusProjectConfig.js +880 -0
- package/dist/nexusProjectHomeService.d.ts +121 -0
- package/dist/nexusProjectHomeService.js +171 -0
- package/dist/nexusProjectLifecycle.d.ts +62 -0
- package/dist/nexusProjectLifecycle.js +205 -0
- package/dist/nexusProjectOperations.d.ts +101 -0
- package/dist/nexusProjectOperations.js +296 -0
- package/dist/nexusProjectRegistry.d.ts +42 -0
- package/dist/nexusProjectRegistry.js +91 -0
- package/dist/nexusProjectScaffold.d.ts +25 -0
- package/dist/nexusProjectScaffold.js +61 -0
- package/dist/nexusProjectTemplate.d.ts +34 -0
- package/dist/nexusProjectTemplate.js +354 -0
- package/dist/nexusSkills.d.ts +134 -0
- package/dist/nexusSkills.js +647 -0
- package/dist/nexusWorkerContextBundle.d.ts +142 -0
- package/dist/nexusWorkerContextBundle.js +375 -0
- package/dist/processSupervisor.d.ts +89 -0
- package/dist/processSupervisor.js +440 -0
- package/dist/vibeKanbanApi.d.ts +11 -0
- package/dist/vibeKanbanApi.js +14 -0
- package/dist/vibeKanbanAuth.d.ts +25 -0
- package/dist/vibeKanbanAuth.js +101 -0
- package/dist/vibeKanbanBoardAdapter.d.ts +36 -0
- package/dist/vibeKanbanBoardAdapter.js +196 -0
- package/dist/vibeKanbanMcpConfig.d.ts +36 -0
- package/dist/vibeKanbanMcpConfig.js +191 -0
- package/dist/vibeKanbanProjectAdapter.d.ts +39 -0
- package/dist/vibeKanbanProjectAdapter.js +113 -0
- package/dist/vibeKanbanWorkspaceSetup.d.ts +1 -0
- package/dist/vibeKanbanWorkspaceSetup.js +96 -0
- package/dist/workItemService.d.ts +60 -0
- package/dist/workItemService.js +163 -0
- package/dist/workTrackingGitHubProvider.d.ts +71 -0
- package/dist/workTrackingGitHubProvider.js +663 -0
- package/dist/workTrackingGitLabProvider.d.ts +62 -0
- package/dist/workTrackingGitLabProvider.js +523 -0
- package/dist/workTrackingJiraProvider.d.ts +67 -0
- package/dist/workTrackingJiraProvider.js +652 -0
- package/dist/workTrackingLocalProvider.d.ts +49 -0
- package/dist/workTrackingLocalProvider.js +463 -0
- package/dist/workTrackingProviderService.d.ts +21 -0
- package/dist/workTrackingProviderService.js +117 -0
- package/dist/workTrackingTypes.d.ts +202 -0
- package/dist/workTrackingTypes.js +1 -0
- package/dist/workTrackingVibeProvider.d.ts +35 -0
- package/dist/workTrackingVibeProvider.js +119 -0
- package/dist/worktreeExecutionMetadata.d.ts +76 -0
- package/dist/worktreeExecutionMetadata.js +239 -0
- package/package.json +37 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { nexusProjectWorktreesDirectoryName, loadProjectConfig, projectConfigPath, projectWorktreesRootPath, saveProjectConfig, } from "./nexusProjectConfig.js";
|
|
4
|
+
import { assertFileDoesNotExist, assertGitRepository, defaultImportedProjectRoot, defaultProjectGitRunner, defaultSourceCheckoutDirectoryName, detectDefaultBranch, detectOriginUrl, directoryExistsAndIsNonEmpty, ensureUniqueProject, loadProjectConfigIfExists, NexusProjectError, optionalNonEmptyString, pathForProjectConfig, runProjectGitCommand, safeProjectDirectoryName, slugify, } from "./nexusProjectLifecycle.js";
|
|
5
|
+
import { findNexusProjectReference, projectRootFromInput, upsertNexusProjectReference, } from "./nexusProjectRegistry.js";
|
|
6
|
+
import { scaffoldNexusProject, } from "./nexusProjectScaffold.js";
|
|
7
|
+
export function buildProjectConfig(name, projectId, from, defaultBranch, vibeKanbanProjectId = null, sourceRoot, forceGit = false, extensions) {
|
|
8
|
+
const repo = {
|
|
9
|
+
kind: from || sourceRoot || forceGit ? "git" : "local",
|
|
10
|
+
remoteUrl: from ?? null,
|
|
11
|
+
defaultBranch,
|
|
12
|
+
...(sourceRoot ? { sourceRoot } : {}),
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
version: 1,
|
|
16
|
+
id: projectId,
|
|
17
|
+
name,
|
|
18
|
+
home: null,
|
|
19
|
+
repo,
|
|
20
|
+
components: [
|
|
21
|
+
{
|
|
22
|
+
id: "primary",
|
|
23
|
+
name,
|
|
24
|
+
kind: repo.kind,
|
|
25
|
+
role: "primary",
|
|
26
|
+
remoteUrl: repo.remoteUrl,
|
|
27
|
+
defaultBranch: repo.defaultBranch,
|
|
28
|
+
sourceRoot: sourceRoot ?? ".",
|
|
29
|
+
relationships: [],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
worktreesRoot: nexusProjectWorktreesDirectoryName,
|
|
33
|
+
kanban: {
|
|
34
|
+
provider: "vibe-kanban",
|
|
35
|
+
projectId: vibeKanbanProjectId,
|
|
36
|
+
},
|
|
37
|
+
...(extensions ? { extensions } : {}),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function buildConfiguredWorkTracking(options) {
|
|
41
|
+
if (options.provider === "local") {
|
|
42
|
+
const storePath = optionalNonEmptyString(options.storePath, "storePath");
|
|
43
|
+
return {
|
|
44
|
+
provider: "local",
|
|
45
|
+
...(storePath !== undefined ? { storePath } : {}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (options.provider === "github") {
|
|
49
|
+
const owner = optionalNonEmptyString(options.repositoryOwner, "repositoryOwner");
|
|
50
|
+
const name = optionalNonEmptyString(options.repositoryName, "repositoryName");
|
|
51
|
+
if (!owner) {
|
|
52
|
+
throw new NexusProjectError("repositoryOwner is required for github tracker configuration");
|
|
53
|
+
}
|
|
54
|
+
if (!name) {
|
|
55
|
+
throw new NexusProjectError("repositoryName is required for github tracker configuration");
|
|
56
|
+
}
|
|
57
|
+
const host = optionalNonEmptyString(options.host, "host");
|
|
58
|
+
return {
|
|
59
|
+
provider: "github",
|
|
60
|
+
...(host !== undefined ? { host } : {}),
|
|
61
|
+
repository: {
|
|
62
|
+
owner,
|
|
63
|
+
name,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (options.provider === "gitlab") {
|
|
68
|
+
const id = optionalNonEmptyString(options.repositoryId, "repositoryId");
|
|
69
|
+
if (!id) {
|
|
70
|
+
throw new NexusProjectError("repositoryId is required for gitlab tracker configuration");
|
|
71
|
+
}
|
|
72
|
+
const host = optionalNonEmptyString(options.host, "host");
|
|
73
|
+
return {
|
|
74
|
+
provider: "gitlab",
|
|
75
|
+
...(host !== undefined ? { host } : {}),
|
|
76
|
+
repository: {
|
|
77
|
+
id,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
if (options.provider === "jira") {
|
|
82
|
+
const host = optionalNonEmptyString(options.host, "host");
|
|
83
|
+
const projectKey = optionalNonEmptyString(options.projectKey, "projectKey");
|
|
84
|
+
const issueType = optionalNonEmptyString(options.issueType, "issueType");
|
|
85
|
+
if (!host) {
|
|
86
|
+
throw new NexusProjectError("host is required for jira tracker configuration");
|
|
87
|
+
}
|
|
88
|
+
if (!projectKey) {
|
|
89
|
+
throw new NexusProjectError("projectKey is required for jira tracker configuration");
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
provider: "jira",
|
|
93
|
+
host,
|
|
94
|
+
projectKey,
|
|
95
|
+
...(issueType !== undefined ? { issueType } : {}),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
throw new NexusProjectError(`Unsupported tracker provider: ${options.provider}`);
|
|
99
|
+
}
|
|
100
|
+
export function createNexusProjectInRegistry(options) {
|
|
101
|
+
if (options.name.trim().length === 0) {
|
|
102
|
+
throw new NexusProjectError("name must be a non-empty string");
|
|
103
|
+
}
|
|
104
|
+
const vibeKanbanProjectId = optionalNonEmptyString(options.vibeKanbanProjectId, "vibeKanbanProjectId") ??
|
|
105
|
+
null;
|
|
106
|
+
if (options.from && options.gitInit) {
|
|
107
|
+
throw new NexusProjectError("--from and --git-init are mutually exclusive");
|
|
108
|
+
}
|
|
109
|
+
const projectId = slugify(options.name);
|
|
110
|
+
const projectRoot = path.resolve(options.root ??
|
|
111
|
+
path.join(options.registry.paths.projectsRoot, safeProjectDirectoryName(options.name)));
|
|
112
|
+
ensureUniqueProject(options.registry, projectId, projectRoot);
|
|
113
|
+
const creatingFromRemote = Boolean(options.from);
|
|
114
|
+
if (directoryExistsAndIsNonEmpty(projectRoot)) {
|
|
115
|
+
throw new NexusProjectError(`Project root already exists and is not empty: ${projectRoot}`);
|
|
116
|
+
}
|
|
117
|
+
const gitRunner = options.gitRunner ?? defaultProjectGitRunner;
|
|
118
|
+
const gitCommands = [];
|
|
119
|
+
let sourceRoot = null;
|
|
120
|
+
if (creatingFromRemote) {
|
|
121
|
+
fs.mkdirSync(projectRoot, { recursive: true });
|
|
122
|
+
runProjectGitCommand(gitRunner, gitCommands, ["init", projectRoot]);
|
|
123
|
+
sourceRoot = path.join(projectRoot, defaultSourceCheckoutDirectoryName);
|
|
124
|
+
runProjectGitCommand(gitRunner, gitCommands, [
|
|
125
|
+
"clone",
|
|
126
|
+
options.from,
|
|
127
|
+
sourceRoot,
|
|
128
|
+
]);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
fs.mkdirSync(projectRoot, { recursive: true });
|
|
132
|
+
runProjectGitCommand(gitRunner, gitCommands, ["init", projectRoot]);
|
|
133
|
+
}
|
|
134
|
+
const defaultBranch = detectDefaultBranch(gitRunner, gitCommands, sourceRoot ?? projectRoot);
|
|
135
|
+
const projectConfig = buildProjectConfig(options.name, projectId, options.from, defaultBranch, vibeKanbanProjectId, sourceRoot ? pathForProjectConfig(projectRoot, sourceRoot) : null, false, options.extensions);
|
|
136
|
+
const devNexusProjectConfigPath = projectConfigPath(projectRoot);
|
|
137
|
+
const worktreesRoot = projectWorktreesRootPath(projectRoot, projectConfig);
|
|
138
|
+
assertFileDoesNotExist(devNexusProjectConfigPath);
|
|
139
|
+
saveProjectConfig(projectRoot, projectConfig);
|
|
140
|
+
const scaffold = scaffoldNexusProject({
|
|
141
|
+
homePath: options.homePath,
|
|
142
|
+
projectRoot,
|
|
143
|
+
worktreesRoot,
|
|
144
|
+
projectConfig,
|
|
145
|
+
skills: projectConfig.skills,
|
|
146
|
+
mcp: projectConfig.mcp,
|
|
147
|
+
extensions: options.scaffoldExtensions,
|
|
148
|
+
});
|
|
149
|
+
const reference = upsertNexusProjectReference(options.registry, projectRoot, projectConfig, { vibeKanbanProjectId });
|
|
150
|
+
return {
|
|
151
|
+
projectRoot,
|
|
152
|
+
projectConfigPath: devNexusProjectConfigPath,
|
|
153
|
+
worktreesRoot,
|
|
154
|
+
projectConfig,
|
|
155
|
+
reference,
|
|
156
|
+
scaffold,
|
|
157
|
+
git: {
|
|
158
|
+
operation: creatingFromRemote ? "clone" : "init",
|
|
159
|
+
remoteUrl: options.from ?? null,
|
|
160
|
+
defaultBranch,
|
|
161
|
+
commands: gitCommands,
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
export function importNexusProjectInRegistry(options) {
|
|
166
|
+
const vibeKanbanProjectId = optionalNonEmptyString(options.vibeKanbanProjectId, "vibeKanbanProjectId") ??
|
|
167
|
+
null;
|
|
168
|
+
const sourceRoot = path.resolve(options.root);
|
|
169
|
+
if (!fs.existsSync(sourceRoot) || !fs.statSync(sourceRoot).isDirectory()) {
|
|
170
|
+
throw new NexusProjectError(`Project source root must be an existing directory: ${sourceRoot}`);
|
|
171
|
+
}
|
|
172
|
+
const gitRunner = options.gitRunner ?? defaultProjectGitRunner;
|
|
173
|
+
const gitCommands = [];
|
|
174
|
+
assertGitRepository(gitRunner, gitCommands, sourceRoot);
|
|
175
|
+
const remoteUrl = detectOriginUrl(gitRunner, gitCommands, sourceRoot);
|
|
176
|
+
const defaultBranch = detectDefaultBranch(gitRunner, gitCommands, sourceRoot);
|
|
177
|
+
const existingProjectConfig = loadProjectConfigIfExists(sourceRoot);
|
|
178
|
+
const projectName = existingProjectConfig?.name ?? options.name ?? path.basename(sourceRoot);
|
|
179
|
+
const projectId = existingProjectConfig?.id ?? slugify(projectName);
|
|
180
|
+
const projectRoot = existingProjectConfig
|
|
181
|
+
? sourceRoot
|
|
182
|
+
: path.resolve(options.projectRoot ??
|
|
183
|
+
defaultImportedProjectRoot(options.registry, projectName, sourceRoot));
|
|
184
|
+
ensureUniqueProject(options.registry, projectId, projectRoot);
|
|
185
|
+
if (!existingProjectConfig && directoryExistsAndIsNonEmpty(projectRoot)) {
|
|
186
|
+
throw new NexusProjectError(`Project root already exists and is not empty: ${projectRoot}`);
|
|
187
|
+
}
|
|
188
|
+
if (!existingProjectConfig) {
|
|
189
|
+
fs.mkdirSync(projectRoot, { recursive: true });
|
|
190
|
+
runProjectGitCommand(gitRunner, gitCommands, ["init", projectRoot]);
|
|
191
|
+
}
|
|
192
|
+
const projectConfig = existingProjectConfig
|
|
193
|
+
? options.extensions
|
|
194
|
+
? {
|
|
195
|
+
...existingProjectConfig,
|
|
196
|
+
extensions: {
|
|
197
|
+
...existingProjectConfig.extensions,
|
|
198
|
+
...options.extensions,
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
: existingProjectConfig
|
|
202
|
+
: buildProjectConfig(projectName, projectId, remoteUrl ?? undefined, defaultBranch, vibeKanbanProjectId, pathForProjectConfig(projectRoot, sourceRoot), true, options.extensions);
|
|
203
|
+
if (existingProjectConfig && vibeKanbanProjectId) {
|
|
204
|
+
projectConfig.kanban = {
|
|
205
|
+
...projectConfig.kanban,
|
|
206
|
+
projectId: vibeKanbanProjectId,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const devNexusProjectConfigPath = projectConfigPath(projectRoot);
|
|
210
|
+
if (!existingProjectConfig || vibeKanbanProjectId || options.extensions) {
|
|
211
|
+
saveProjectConfig(projectRoot, projectConfig);
|
|
212
|
+
}
|
|
213
|
+
const worktreesRoot = projectWorktreesRootPath(projectRoot, projectConfig);
|
|
214
|
+
const scaffold = scaffoldNexusProject({
|
|
215
|
+
homePath: options.homePath,
|
|
216
|
+
projectRoot,
|
|
217
|
+
worktreesRoot,
|
|
218
|
+
projectConfig,
|
|
219
|
+
skills: projectConfig.skills,
|
|
220
|
+
mcp: projectConfig.mcp,
|
|
221
|
+
extensions: options.scaffoldExtensions,
|
|
222
|
+
});
|
|
223
|
+
const reference = upsertNexusProjectReference(options.registry, projectRoot, projectConfig, { vibeKanbanProjectId: projectConfig.kanban.projectId });
|
|
224
|
+
return {
|
|
225
|
+
projectRoot,
|
|
226
|
+
projectConfigPath: devNexusProjectConfigPath,
|
|
227
|
+
worktreesRoot,
|
|
228
|
+
projectConfig,
|
|
229
|
+
reference,
|
|
230
|
+
scaffold,
|
|
231
|
+
git: {
|
|
232
|
+
operation: "import",
|
|
233
|
+
remoteUrl,
|
|
234
|
+
defaultBranch,
|
|
235
|
+
commands: gitCommands,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
export function configureNexusProjectTrackerInRegistry(options) {
|
|
240
|
+
const existingReference = findNexusProjectReference(options.registry, options.project);
|
|
241
|
+
const projectRoot = existingReference
|
|
242
|
+
? path.resolve(existingReference.projectRoot)
|
|
243
|
+
: projectRootFromInput(options.project);
|
|
244
|
+
const projectConfig = loadProjectConfigIfExists(projectRoot);
|
|
245
|
+
if (!projectConfig) {
|
|
246
|
+
throw new NexusProjectError(`DevNexus project is not initialized: ${projectConfigPath(projectRoot)}`);
|
|
247
|
+
}
|
|
248
|
+
const workTracking = buildConfiguredWorkTracking(options);
|
|
249
|
+
const updatedProjectConfig = {
|
|
250
|
+
...projectConfig,
|
|
251
|
+
workTracking,
|
|
252
|
+
components: projectConfig.components.map((component) => component.role === "primary"
|
|
253
|
+
? {
|
|
254
|
+
...component,
|
|
255
|
+
workTracking,
|
|
256
|
+
}
|
|
257
|
+
: component),
|
|
258
|
+
};
|
|
259
|
+
const projectConfigFilePath = saveProjectConfig(projectRoot, updatedProjectConfig);
|
|
260
|
+
const reference = upsertNexusProjectReference(options.registry, projectRoot, updatedProjectConfig, { vibeKanbanProjectId: null });
|
|
261
|
+
return {
|
|
262
|
+
projectRoot,
|
|
263
|
+
projectConfigPath: projectConfigFilePath,
|
|
264
|
+
projectConfig: updatedProjectConfig,
|
|
265
|
+
reference,
|
|
266
|
+
workTracking,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
export function linkNexusProjectTrackerInRegistry(options) {
|
|
270
|
+
const vibeKanbanProjectId = optionalNonEmptyString(options.trackerProjectId, "trackerProjectId");
|
|
271
|
+
if (!vibeKanbanProjectId) {
|
|
272
|
+
throw new NexusProjectError("trackerProjectId must be a non-empty string");
|
|
273
|
+
}
|
|
274
|
+
const existingReference = findNexusProjectReference(options.registry, options.project);
|
|
275
|
+
const projectRoot = existingReference
|
|
276
|
+
? path.resolve(existingReference.projectRoot)
|
|
277
|
+
: projectRootFromInput(options.project);
|
|
278
|
+
const projectConfig = loadProjectConfig(projectRoot);
|
|
279
|
+
const updatedProjectConfig = {
|
|
280
|
+
...projectConfig,
|
|
281
|
+
kanban: {
|
|
282
|
+
...projectConfig.kanban,
|
|
283
|
+
projectId: vibeKanbanProjectId,
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
const projectConfigFilePath = saveProjectConfig(projectRoot, updatedProjectConfig);
|
|
287
|
+
const reference = upsertNexusProjectReference(options.registry, projectRoot, updatedProjectConfig, { vibeKanbanProjectId });
|
|
288
|
+
return {
|
|
289
|
+
projectRoot,
|
|
290
|
+
projectConfigPath: projectConfigFilePath,
|
|
291
|
+
projectConfig: updatedProjectConfig,
|
|
292
|
+
reference,
|
|
293
|
+
vibeKanbanProjectId,
|
|
294
|
+
vibeKanbanRepoId: reference.vibeKanbanRepoId ?? null,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type NexusProjectConfig } from "./nexusProjectConfig.js";
|
|
2
|
+
import { type ResolvedNexusProjectComponent } from "./nexusProjectLifecycle.js";
|
|
3
|
+
import type { WorkTrackingConfig } from "./workTrackingTypes.js";
|
|
4
|
+
export interface NexusProjectReference {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
vibeKanbanProjectId?: string;
|
|
9
|
+
vibeKanbanRepoId?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface NexusProjectRegistry {
|
|
12
|
+
projects: NexusProjectReference[];
|
|
13
|
+
}
|
|
14
|
+
export interface NexusProjectStatusBase {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
projectRoot: string;
|
|
18
|
+
repo: NexusProjectConfig["repo"] | null;
|
|
19
|
+
components: ResolvedNexusProjectComponent[];
|
|
20
|
+
workTracking: WorkTrackingConfig | null;
|
|
21
|
+
vibeKanbanProjectId: string | null;
|
|
22
|
+
vibeKanbanRepoId: string | null;
|
|
23
|
+
projectConfigPath: string;
|
|
24
|
+
projectConfigExists: boolean;
|
|
25
|
+
worktreesRoot: string;
|
|
26
|
+
worktreesRootExists: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface BuildNexusProjectStatusOptions {
|
|
29
|
+
projectConfig?: NexusProjectConfig;
|
|
30
|
+
}
|
|
31
|
+
export interface UpsertNexusProjectReferenceOptions {
|
|
32
|
+
vibeKanbanProjectId?: string | null;
|
|
33
|
+
vibeKanbanRepoId?: string | null;
|
|
34
|
+
}
|
|
35
|
+
export declare function projectRootFromInput(input: string): string;
|
|
36
|
+
export declare function findNexusProjectReferenceById(registry: NexusProjectRegistry, id: string): NexusProjectReference | undefined;
|
|
37
|
+
export declare function findNexusProjectReferenceByPath(registry: NexusProjectRegistry, projectPath: string): NexusProjectReference | undefined;
|
|
38
|
+
export declare function findNexusProjectReference(registry: NexusProjectRegistry, idOrPath: string): NexusProjectReference | undefined;
|
|
39
|
+
export declare function buildNexusProjectStatus(reference: NexusProjectReference, options?: BuildNexusProjectStatusOptions): NexusProjectStatusBase;
|
|
40
|
+
export declare function buildNexusProjectStatusForPath(projectRoot: string): NexusProjectStatusBase;
|
|
41
|
+
export declare function upsertNexusProjectReference(registry: NexusProjectRegistry, projectRoot: string, projectConfig: NexusProjectConfig, options?: UpsertNexusProjectReferenceOptions): NexusProjectReference;
|
|
42
|
+
export declare function loadRequiredProjectConfig(projectRoot: string): NexusProjectConfig;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { devNexusProjectConfigFileName, loadProjectConfig, projectConfigPath, projectWorktreesRootPath, } from "./nexusProjectConfig.js";
|
|
4
|
+
import { ensureUniqueProject, loadProjectConfigIfExists, NexusProjectError, resolveProjectComponents, samePath, } from "./nexusProjectLifecycle.js";
|
|
5
|
+
export function projectRootFromInput(input) {
|
|
6
|
+
const resolved = path.resolve(input);
|
|
7
|
+
return path.basename(resolved) === devNexusProjectConfigFileName
|
|
8
|
+
? path.dirname(resolved)
|
|
9
|
+
: resolved;
|
|
10
|
+
}
|
|
11
|
+
export function findNexusProjectReferenceById(registry, id) {
|
|
12
|
+
return (registry.projects.find((project) => project.id === id) ??
|
|
13
|
+
registry.projects.find((project) => loadProjectConfigIfExists(path.resolve(project.projectRoot))?.id === id));
|
|
14
|
+
}
|
|
15
|
+
export function findNexusProjectReferenceByPath(registry, projectPath) {
|
|
16
|
+
const projectRoot = projectRootFromInput(projectPath);
|
|
17
|
+
return registry.projects.find((project) => samePath(project.projectRoot, projectRoot));
|
|
18
|
+
}
|
|
19
|
+
export function findNexusProjectReference(registry, idOrPath) {
|
|
20
|
+
return (findNexusProjectReferenceById(registry, idOrPath) ??
|
|
21
|
+
findNexusProjectReferenceByPath(registry, idOrPath));
|
|
22
|
+
}
|
|
23
|
+
export function buildNexusProjectStatus(reference, options = {}) {
|
|
24
|
+
const projectRoot = path.resolve(reference.projectRoot);
|
|
25
|
+
const config = options.projectConfig ?? loadProjectConfigIfExists(projectRoot);
|
|
26
|
+
const resolvedProjectConfigPath = projectConfigPath(projectRoot);
|
|
27
|
+
const resolvedWorktreesRoot = projectWorktreesRootPath(projectRoot, config);
|
|
28
|
+
const components = config ? resolveProjectComponents(projectRoot, config) : [];
|
|
29
|
+
return {
|
|
30
|
+
id: config?.id ?? reference.id,
|
|
31
|
+
name: config?.name ?? reference.name,
|
|
32
|
+
projectRoot,
|
|
33
|
+
repo: config?.repo ?? null,
|
|
34
|
+
components,
|
|
35
|
+
workTracking: config?.workTracking ?? null,
|
|
36
|
+
vibeKanbanProjectId: config?.kanban.projectId ?? reference.vibeKanbanProjectId ?? null,
|
|
37
|
+
vibeKanbanRepoId: reference.vibeKanbanRepoId ?? null,
|
|
38
|
+
projectConfigPath: resolvedProjectConfigPath,
|
|
39
|
+
projectConfigExists: Boolean(config),
|
|
40
|
+
worktreesRoot: resolvedWorktreesRoot,
|
|
41
|
+
worktreesRootExists: fs.existsSync(resolvedWorktreesRoot),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function buildNexusProjectStatusForPath(projectRoot) {
|
|
45
|
+
const config = loadProjectConfigIfExists(projectRoot);
|
|
46
|
+
if (!config) {
|
|
47
|
+
throw new NexusProjectError(`DevNexus project is not initialized: ${projectConfigPath(projectRoot)}`);
|
|
48
|
+
}
|
|
49
|
+
return buildNexusProjectStatus({
|
|
50
|
+
id: config.id,
|
|
51
|
+
name: config.name,
|
|
52
|
+
projectRoot,
|
|
53
|
+
...(config.kanban.projectId
|
|
54
|
+
? { vibeKanbanProjectId: config.kanban.projectId }
|
|
55
|
+
: {}),
|
|
56
|
+
}, { projectConfig: config });
|
|
57
|
+
}
|
|
58
|
+
export function upsertNexusProjectReference(registry, projectRoot, projectConfig, options = {}) {
|
|
59
|
+
const existingIndex = registry.projects.findIndex((project) => samePath(project.projectRoot, projectRoot));
|
|
60
|
+
const existing = existingIndex >= 0 ? registry.projects[existingIndex] : undefined;
|
|
61
|
+
const resolvedVibeKanbanProjectId = options.vibeKanbanProjectId ??
|
|
62
|
+
projectConfig.kanban.projectId ??
|
|
63
|
+
existing?.vibeKanbanProjectId ??
|
|
64
|
+
null;
|
|
65
|
+
const resolvedVibeKanbanRepoId = options.vibeKanbanRepoId ?? existing?.vibeKanbanRepoId ?? null;
|
|
66
|
+
const reference = {
|
|
67
|
+
id: projectConfig.id,
|
|
68
|
+
name: projectConfig.name,
|
|
69
|
+
projectRoot,
|
|
70
|
+
...(resolvedVibeKanbanProjectId
|
|
71
|
+
? { vibeKanbanProjectId: resolvedVibeKanbanProjectId }
|
|
72
|
+
: {}),
|
|
73
|
+
...(resolvedVibeKanbanRepoId
|
|
74
|
+
? { vibeKanbanRepoId: resolvedVibeKanbanRepoId }
|
|
75
|
+
: {}),
|
|
76
|
+
};
|
|
77
|
+
if (existingIndex >= 0) {
|
|
78
|
+
registry.projects[existingIndex] = reference;
|
|
79
|
+
return reference;
|
|
80
|
+
}
|
|
81
|
+
const duplicateId = registry.projects.find((project) => project.id === projectConfig.id);
|
|
82
|
+
if (duplicateId) {
|
|
83
|
+
throw new NexusProjectError(`Project id is already registered at another root: ${duplicateId.id}`);
|
|
84
|
+
}
|
|
85
|
+
ensureUniqueProject(registry, projectConfig.id, projectRoot);
|
|
86
|
+
registry.projects.push(reference);
|
|
87
|
+
return reference;
|
|
88
|
+
}
|
|
89
|
+
export function loadRequiredProjectConfig(projectRoot) {
|
|
90
|
+
return loadProjectConfig(projectRoot);
|
|
91
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { NexusExtension } from "./nexusExtension.js";
|
|
2
|
+
import { type MaterializeNexusProjectAgentMcpConfigResult } from "./nexusAgentMcpConfig.js";
|
|
3
|
+
import type { NexusProjectMcpConfig } from "./nexusProjectConfig.js";
|
|
4
|
+
import type { NexusProjectConfig } from "./nexusProjectConfig.js";
|
|
5
|
+
import { type MaterializeNexusProjectTemplateResult } from "./nexusProjectTemplate.js";
|
|
6
|
+
import { type MaterializeNexusProjectSkillsResult, type NexusProjectSkillsConfig, type NexusSkillDefinition } from "./nexusSkills.js";
|
|
7
|
+
export interface ScaffoldNexusProjectOptions<ProjectConfig extends NexusProjectConfig = NexusProjectConfig> {
|
|
8
|
+
homePath: string;
|
|
9
|
+
projectRoot: string;
|
|
10
|
+
worktreesRoot: string;
|
|
11
|
+
projectConfig: ProjectConfig;
|
|
12
|
+
extensions?: NexusExtension<ProjectConfig>[];
|
|
13
|
+
skills?: NexusProjectSkillsConfig | false;
|
|
14
|
+
skillDefinitions?: NexusSkillDefinition[];
|
|
15
|
+
mcp?: NexusProjectMcpConfig | false;
|
|
16
|
+
}
|
|
17
|
+
export interface ScaffoldNexusProjectResult {
|
|
18
|
+
projectRoot: string;
|
|
19
|
+
worktreesRoot: string;
|
|
20
|
+
template: MaterializeNexusProjectTemplateResult;
|
|
21
|
+
skills: MaterializeNexusProjectSkillsResult;
|
|
22
|
+
agentMcp: MaterializeNexusProjectAgentMcpConfigResult;
|
|
23
|
+
extensionResults: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
export declare function scaffoldNexusProject<ProjectConfig extends NexusProjectConfig = NexusProjectConfig>(options: ScaffoldNexusProjectOptions<ProjectConfig>): ScaffoldNexusProjectResult;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { emptyNexusProjectAgentMcpConfigResult, materializeNexusProjectAgentMcpConfig, } from "./nexusAgentMcpConfig.js";
|
|
2
|
+
import { materializeNexusProjectTemplate, } from "./nexusProjectTemplate.js";
|
|
3
|
+
import { materializeNexusProjectSkills, } from "./nexusSkills.js";
|
|
4
|
+
export function scaffoldNexusProject(options) {
|
|
5
|
+
const context = {
|
|
6
|
+
homePath: options.homePath,
|
|
7
|
+
projectRoot: options.projectRoot,
|
|
8
|
+
worktreesRoot: options.worktreesRoot,
|
|
9
|
+
projectConfig: options.projectConfig,
|
|
10
|
+
};
|
|
11
|
+
const skillsContext = context;
|
|
12
|
+
const extensionResults = {};
|
|
13
|
+
const extensionSkills = [];
|
|
14
|
+
for (const extension of options.extensions ?? []) {
|
|
15
|
+
const skills = extension.projectSkills?.(skillsContext);
|
|
16
|
+
if (skills) {
|
|
17
|
+
extensionSkills.push(...skills);
|
|
18
|
+
}
|
|
19
|
+
if (!extension.installProjectFiles) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
extensionResults[extension.id] = extension.installProjectFiles(context);
|
|
23
|
+
}
|
|
24
|
+
const template = materializeNexusProjectTemplate({
|
|
25
|
+
projectRoot: options.projectRoot,
|
|
26
|
+
worktreesRoot: options.worktreesRoot,
|
|
27
|
+
projectConfig: options.projectConfig,
|
|
28
|
+
skillsConfig: options.skills,
|
|
29
|
+
mcpConfig: options.mcp,
|
|
30
|
+
});
|
|
31
|
+
const skills = options.skills === false
|
|
32
|
+
? {
|
|
33
|
+
skillsDirectory: "",
|
|
34
|
+
installed: [],
|
|
35
|
+
agentTargets: [],
|
|
36
|
+
gitExcludePath: null,
|
|
37
|
+
gitExcludeEntries: [],
|
|
38
|
+
}
|
|
39
|
+
: materializeNexusProjectSkills({
|
|
40
|
+
projectRoot: options.projectRoot,
|
|
41
|
+
skillsConfig: options.skills,
|
|
42
|
+
skillDefinitions: [
|
|
43
|
+
...extensionSkills,
|
|
44
|
+
...(options.skillDefinitions ?? []),
|
|
45
|
+
],
|
|
46
|
+
});
|
|
47
|
+
const agentMcp = options.mcp === undefined || options.mcp === false
|
|
48
|
+
? emptyNexusProjectAgentMcpConfigResult()
|
|
49
|
+
: materializeNexusProjectAgentMcpConfig({
|
|
50
|
+
projectRoot: options.projectRoot,
|
|
51
|
+
mcpConfig: options.mcp,
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
projectRoot: options.projectRoot,
|
|
55
|
+
worktreesRoot: options.worktreesRoot,
|
|
56
|
+
template,
|
|
57
|
+
skills,
|
|
58
|
+
agentMcp,
|
|
59
|
+
extensionResults,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { NexusProjectMcpConfig } from "./nexusProjectConfig.js";
|
|
2
|
+
import { type NexusProjectConfig } from "./nexusProjectConfig.js";
|
|
3
|
+
import type { NexusProjectSkillsConfig, NexusSkillSourceControl } from "./nexusSkills.js";
|
|
4
|
+
export type NexusProjectTemplateArea = "project_state" | "component_configuration" | "target_state" | "skills" | "agent_mcp_projection";
|
|
5
|
+
export type NexusProjectTemplateOwner = "generated" | "user_authored" | "local_runtime";
|
|
6
|
+
export interface NexusProjectTemplateEntry {
|
|
7
|
+
area: NexusProjectTemplateArea;
|
|
8
|
+
owner: NexusProjectTemplateOwner;
|
|
9
|
+
path: string;
|
|
10
|
+
sourceControl: NexusSkillSourceControl | "local";
|
|
11
|
+
description: string;
|
|
12
|
+
}
|
|
13
|
+
export interface NexusProjectTemplateLayout {
|
|
14
|
+
entries: NexusProjectTemplateEntry[];
|
|
15
|
+
migrationNotes: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface MaterializeNexusProjectTemplateOptions {
|
|
18
|
+
projectRoot: string;
|
|
19
|
+
worktreesRoot: string;
|
|
20
|
+
projectConfig: NexusProjectConfig;
|
|
21
|
+
skillsConfig?: NexusProjectSkillsConfig | false;
|
|
22
|
+
mcpConfig?: NexusProjectMcpConfig | false;
|
|
23
|
+
excludeFromGit?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface MaterializeNexusProjectTemplateResult extends NexusProjectTemplateLayout {
|
|
26
|
+
supportReadmePath: string;
|
|
27
|
+
targetStatePath: string | null;
|
|
28
|
+
componentWorktreesRoots: string[];
|
|
29
|
+
gitExcludePath: string | null;
|
|
30
|
+
gitExcludeEntries: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare function buildNexusProjectTemplateLayout(options: Omit<MaterializeNexusProjectTemplateOptions, "excludeFromGit">): NexusProjectTemplateLayout;
|
|
33
|
+
export declare function materializeNexusProjectTemplate(options: MaterializeNexusProjectTemplateOptions): MaterializeNexusProjectTemplateResult;
|
|
34
|
+
export declare function nexusProjectTemplateMigrationNotes(): string[];
|