@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.
Files changed (100) hide show
  1. package/README.md +677 -0
  2. package/dist/browserOpener.d.ts +9 -0
  3. package/dist/browserOpener.js +47 -0
  4. package/dist/cli.d.ts +18 -0
  5. package/dist/cli.js +2374 -0
  6. package/dist/gitWorktreeService.d.ts +57 -0
  7. package/dist/gitWorktreeService.js +157 -0
  8. package/dist/index.d.ts +47 -0
  9. package/dist/index.js +47 -0
  10. package/dist/nexusAgentMcpConfig.d.ts +30 -0
  11. package/dist/nexusAgentMcpConfig.js +228 -0
  12. package/dist/nexusAutomation.d.ts +103 -0
  13. package/dist/nexusAutomation.js +390 -0
  14. package/dist/nexusAutomationAgentLaunch.d.ts +148 -0
  15. package/dist/nexusAutomationAgentLaunch.js +855 -0
  16. package/dist/nexusAutomationAgentProfile.d.ts +39 -0
  17. package/dist/nexusAutomationAgentProfile.js +103 -0
  18. package/dist/nexusAutomationAgentSurface.d.ts +62 -0
  19. package/dist/nexusAutomationAgentSurface.js +90 -0
  20. package/dist/nexusAutomationCommandExecutor.d.ts +29 -0
  21. package/dist/nexusAutomationCommandExecutor.js +251 -0
  22. package/dist/nexusAutomationConfig.d.ts +114 -0
  23. package/dist/nexusAutomationConfig.js +547 -0
  24. package/dist/nexusAutomationEnqueue.d.ts +37 -0
  25. package/dist/nexusAutomationEnqueue.js +128 -0
  26. package/dist/nexusAutomationRunOnce.d.ts +91 -0
  27. package/dist/nexusAutomationRunOnce.js +586 -0
  28. package/dist/nexusAutomationScheduler.d.ts +50 -0
  29. package/dist/nexusAutomationScheduler.js +196 -0
  30. package/dist/nexusAutomationStatus.d.ts +55 -0
  31. package/dist/nexusAutomationStatus.js +462 -0
  32. package/dist/nexusAutomationTarget.d.ts +19 -0
  33. package/dist/nexusAutomationTarget.js +33 -0
  34. package/dist/nexusAutomationTargetCycle.d.ts +90 -0
  35. package/dist/nexusAutomationTargetCycle.js +282 -0
  36. package/dist/nexusAutomationTargetReport.d.ts +136 -0
  37. package/dist/nexusAutomationTargetReport.js +504 -0
  38. package/dist/nexusAutomationWorktreeSetup.d.ts +89 -0
  39. package/dist/nexusAutomationWorktreeSetup.js +661 -0
  40. package/dist/nexusCoordination.d.ts +198 -0
  41. package/dist/nexusCoordination.js +1018 -0
  42. package/dist/nexusExtension.d.ts +31 -0
  43. package/dist/nexusExtension.js +1 -0
  44. package/dist/nexusHomeConfig.d.ts +38 -0
  45. package/dist/nexusHomeConfig.js +133 -0
  46. package/dist/nexusMcpServer.d.ts +31 -0
  47. package/dist/nexusMcpServer.js +1036 -0
  48. package/dist/nexusPluginCapabilities.d.ts +197 -0
  49. package/dist/nexusPluginCapabilities.js +201 -0
  50. package/dist/nexusProjectConfig.d.ts +95 -0
  51. package/dist/nexusProjectConfig.js +880 -0
  52. package/dist/nexusProjectHomeService.d.ts +121 -0
  53. package/dist/nexusProjectHomeService.js +171 -0
  54. package/dist/nexusProjectLifecycle.d.ts +62 -0
  55. package/dist/nexusProjectLifecycle.js +205 -0
  56. package/dist/nexusProjectOperations.d.ts +101 -0
  57. package/dist/nexusProjectOperations.js +296 -0
  58. package/dist/nexusProjectRegistry.d.ts +42 -0
  59. package/dist/nexusProjectRegistry.js +91 -0
  60. package/dist/nexusProjectScaffold.d.ts +25 -0
  61. package/dist/nexusProjectScaffold.js +61 -0
  62. package/dist/nexusProjectTemplate.d.ts +34 -0
  63. package/dist/nexusProjectTemplate.js +354 -0
  64. package/dist/nexusSkills.d.ts +134 -0
  65. package/dist/nexusSkills.js +647 -0
  66. package/dist/nexusWorkerContextBundle.d.ts +142 -0
  67. package/dist/nexusWorkerContextBundle.js +375 -0
  68. package/dist/processSupervisor.d.ts +89 -0
  69. package/dist/processSupervisor.js +440 -0
  70. package/dist/vibeKanbanApi.d.ts +11 -0
  71. package/dist/vibeKanbanApi.js +14 -0
  72. package/dist/vibeKanbanAuth.d.ts +25 -0
  73. package/dist/vibeKanbanAuth.js +101 -0
  74. package/dist/vibeKanbanBoardAdapter.d.ts +36 -0
  75. package/dist/vibeKanbanBoardAdapter.js +196 -0
  76. package/dist/vibeKanbanMcpConfig.d.ts +36 -0
  77. package/dist/vibeKanbanMcpConfig.js +191 -0
  78. package/dist/vibeKanbanProjectAdapter.d.ts +39 -0
  79. package/dist/vibeKanbanProjectAdapter.js +113 -0
  80. package/dist/vibeKanbanWorkspaceSetup.d.ts +1 -0
  81. package/dist/vibeKanbanWorkspaceSetup.js +96 -0
  82. package/dist/workItemService.d.ts +60 -0
  83. package/dist/workItemService.js +163 -0
  84. package/dist/workTrackingGitHubProvider.d.ts +71 -0
  85. package/dist/workTrackingGitHubProvider.js +663 -0
  86. package/dist/workTrackingGitLabProvider.d.ts +62 -0
  87. package/dist/workTrackingGitLabProvider.js +523 -0
  88. package/dist/workTrackingJiraProvider.d.ts +67 -0
  89. package/dist/workTrackingJiraProvider.js +652 -0
  90. package/dist/workTrackingLocalProvider.d.ts +49 -0
  91. package/dist/workTrackingLocalProvider.js +463 -0
  92. package/dist/workTrackingProviderService.d.ts +21 -0
  93. package/dist/workTrackingProviderService.js +117 -0
  94. package/dist/workTrackingTypes.d.ts +202 -0
  95. package/dist/workTrackingTypes.js +1 -0
  96. package/dist/workTrackingVibeProvider.d.ts +35 -0
  97. package/dist/workTrackingVibeProvider.js +119 -0
  98. package/dist/worktreeExecutionMetadata.d.ts +76 -0
  99. package/dist/worktreeExecutionMetadata.js +239 -0
  100. package/package.json +37 -0
@@ -0,0 +1,547 @@
1
+ export const defaultNexusAutomationConfig = {
2
+ enabled: true,
3
+ mode: "run_once",
4
+ selector: {
5
+ statuses: ["ready", "todo"],
6
+ labels: [],
7
+ excludeLabels: [],
8
+ assignees: [],
9
+ search: null,
10
+ limit: 10,
11
+ },
12
+ verification: {
13
+ focusedCommands: [],
14
+ fullCommands: [],
15
+ requirePassing: true,
16
+ },
17
+ ledger: {
18
+ path: ".dev-nexus/automation/runs.json",
19
+ retention: 200,
20
+ },
21
+ lock: {
22
+ path: ".dev-nexus/automation/run.lock",
23
+ staleAfterMs: 60 * 60 * 1000,
24
+ },
25
+ backoff: {
26
+ failureLimit: 3,
27
+ baseDelayMs: 5 * 60 * 1000,
28
+ maxDelayMs: 60 * 60 * 1000,
29
+ },
30
+ schedule: {
31
+ enabled: true,
32
+ intervalMs: 15 * 60 * 1000,
33
+ },
34
+ setup: {
35
+ dependencyLinks: [],
36
+ },
37
+ executor: {
38
+ command: null,
39
+ timeoutMs: null,
40
+ runFullVerification: false,
41
+ },
42
+ agent: {
43
+ command: null,
44
+ timeoutMs: null,
45
+ coordinatorProfileId: null,
46
+ maxConcurrentSubagents: 1,
47
+ profiles: [],
48
+ relaunch: {
49
+ whileEligible: false,
50
+ },
51
+ },
52
+ target: {
53
+ id: null,
54
+ objective: null,
55
+ statePath: ".dev-nexus/automation/target-state.md",
56
+ cycleLedgerPath: ".dev-nexus/automation/target-cycles.json",
57
+ stopWhenNoEligibleWork: true,
58
+ maxCycles: null,
59
+ maxWorkItems: null,
60
+ },
61
+ safety: {
62
+ profile: "local",
63
+ allowHostMutation: false,
64
+ allowDependencyInstall: false,
65
+ allowLiveServices: false,
66
+ },
67
+ publication: {
68
+ strategy: "review_handoff",
69
+ remote: "origin",
70
+ targetBranch: null,
71
+ push: false,
72
+ },
73
+ };
74
+ export class NexusAutomationConfigError extends Error {
75
+ constructor(message) {
76
+ super(message);
77
+ this.name = "NexusAutomationConfigError";
78
+ }
79
+ }
80
+ export function validateNexusAutomationConfig(value) {
81
+ if (value === undefined) {
82
+ return undefined;
83
+ }
84
+ const record = assertRecord(value, "project config.automation");
85
+ const enabled = optionalBoolean(record, "enabled", "project config.automation");
86
+ const mode = validateMode(record.mode, "project config.automation.mode");
87
+ const selector = validateSelectorConfig(record.selector);
88
+ const verification = validateVerificationConfig(record.verification);
89
+ const ledger = validateLedgerConfig(record.ledger);
90
+ const lock = validateLockConfig(record.lock);
91
+ const backoff = validateBackoffConfig(record.backoff);
92
+ const schedule = validateScheduleConfig(record.schedule);
93
+ const setup = validateSetupConfig(record.setup);
94
+ const executor = validateExecutorConfig(record.executor);
95
+ const agent = validateAgentConfig(record.agent);
96
+ const target = validateTargetConfig(record.target);
97
+ const safety = validateSafetyConfig(record.safety);
98
+ const publication = validatePublicationConfig(record.publication);
99
+ return {
100
+ enabled: enabled ?? defaultNexusAutomationConfig.enabled,
101
+ mode: mode ?? defaultNexusAutomationConfig.mode,
102
+ selector: {
103
+ ...defaultNexusAutomationConfig.selector,
104
+ ...selector,
105
+ },
106
+ verification: {
107
+ ...defaultNexusAutomationConfig.verification,
108
+ ...verification,
109
+ },
110
+ ledger: {
111
+ ...defaultNexusAutomationConfig.ledger,
112
+ ...ledger,
113
+ },
114
+ lock: {
115
+ ...defaultNexusAutomationConfig.lock,
116
+ ...lock,
117
+ },
118
+ backoff: {
119
+ ...defaultNexusAutomationConfig.backoff,
120
+ ...backoff,
121
+ },
122
+ schedule: {
123
+ ...defaultNexusAutomationConfig.schedule,
124
+ ...schedule,
125
+ },
126
+ setup: {
127
+ ...defaultNexusAutomationConfig.setup,
128
+ ...setup,
129
+ },
130
+ executor: {
131
+ ...defaultNexusAutomationConfig.executor,
132
+ ...executor,
133
+ },
134
+ agent: {
135
+ ...defaultNexusAutomationConfig.agent,
136
+ ...agent,
137
+ relaunch: {
138
+ ...defaultNexusAutomationConfig.agent.relaunch,
139
+ ...agent.relaunch,
140
+ },
141
+ },
142
+ target: {
143
+ ...defaultNexusAutomationConfig.target,
144
+ ...target,
145
+ },
146
+ safety: {
147
+ ...defaultNexusAutomationConfig.safety,
148
+ ...safety,
149
+ },
150
+ publication: {
151
+ ...defaultNexusAutomationConfig.publication,
152
+ ...publication,
153
+ },
154
+ };
155
+ }
156
+ function validateMode(value, pathName) {
157
+ if (value === undefined) {
158
+ return undefined;
159
+ }
160
+ if (value === "run_once" || value === "agent_launch") {
161
+ return value;
162
+ }
163
+ throw new NexusAutomationConfigError(`${pathName} must be run_once or agent_launch`);
164
+ }
165
+ function validateSelectorConfig(value) {
166
+ if (value === undefined) {
167
+ return {};
168
+ }
169
+ const pathName = "project config.automation.selector";
170
+ const record = assertRecord(value, pathName);
171
+ return {
172
+ ...optionalArrayField(record, "statuses", pathName, validateWorkStatus),
173
+ ...optionalArrayField(record, "labels", pathName, requiredNonEmptyString),
174
+ ...optionalArrayField(record, "excludeLabels", pathName, requiredNonEmptyString),
175
+ ...optionalArrayField(record, "assignees", pathName, requiredNonEmptyString),
176
+ ...optionalNullableStringField(record, "search", pathName),
177
+ ...optionalPositiveIntegerField(record, "limit", pathName),
178
+ };
179
+ }
180
+ function validateVerificationConfig(value) {
181
+ if (value === undefined) {
182
+ return {};
183
+ }
184
+ const pathName = "project config.automation.verification";
185
+ const record = assertRecord(value, pathName);
186
+ return {
187
+ ...optionalArrayField(record, "focusedCommands", pathName, requiredNonEmptyString),
188
+ ...optionalArrayField(record, "fullCommands", pathName, requiredNonEmptyString),
189
+ ...optionalBooleanField(record, "requirePassing", pathName),
190
+ };
191
+ }
192
+ function validateLedgerConfig(value) {
193
+ if (value === undefined) {
194
+ return {};
195
+ }
196
+ const pathName = "project config.automation.ledger";
197
+ const record = assertRecord(value, pathName);
198
+ return {
199
+ ...optionalStringField(record, "path", pathName),
200
+ ...optionalPositiveIntegerField(record, "retention", pathName),
201
+ };
202
+ }
203
+ function validateLockConfig(value) {
204
+ if (value === undefined) {
205
+ return {};
206
+ }
207
+ const pathName = "project config.automation.lock";
208
+ const record = assertRecord(value, pathName);
209
+ return {
210
+ ...optionalStringField(record, "path", pathName),
211
+ ...optionalPositiveIntegerField(record, "staleAfterMs", pathName),
212
+ };
213
+ }
214
+ function validateBackoffConfig(value) {
215
+ if (value === undefined) {
216
+ return {};
217
+ }
218
+ const pathName = "project config.automation.backoff";
219
+ const record = assertRecord(value, pathName);
220
+ return {
221
+ ...optionalPositiveIntegerField(record, "failureLimit", pathName),
222
+ ...optionalPositiveIntegerField(record, "baseDelayMs", pathName),
223
+ ...optionalPositiveIntegerField(record, "maxDelayMs", pathName),
224
+ };
225
+ }
226
+ function validateScheduleConfig(value) {
227
+ if (value === undefined) {
228
+ return {};
229
+ }
230
+ const pathName = "project config.automation.schedule";
231
+ const record = assertRecord(value, pathName);
232
+ return {
233
+ ...optionalBooleanField(record, "enabled", pathName),
234
+ ...optionalPositiveIntegerField(record, "intervalMs", pathName),
235
+ };
236
+ }
237
+ function validateSetupConfig(value) {
238
+ if (value === undefined) {
239
+ return {};
240
+ }
241
+ const pathName = "project config.automation.setup";
242
+ const record = assertRecord(value, pathName);
243
+ const dependencyLinks = record.dependencyLinks;
244
+ if (dependencyLinks === undefined) {
245
+ return {};
246
+ }
247
+ if (!Array.isArray(dependencyLinks)) {
248
+ throw new NexusAutomationConfigError(`${pathName}.dependencyLinks must be an array`);
249
+ }
250
+ return {
251
+ dependencyLinks: dependencyLinks.map((link, index) => validateDependencyLinkConfig(link, `${pathName}.dependencyLinks[${index}]`)),
252
+ };
253
+ }
254
+ function validateExecutorConfig(value) {
255
+ if (value === undefined) {
256
+ return {};
257
+ }
258
+ const pathName = "project config.automation.executor";
259
+ const record = assertRecord(value, pathName);
260
+ return {
261
+ ...optionalNullableStringField(record, "command", pathName),
262
+ ...optionalNullablePositiveIntegerField(record, "timeoutMs", pathName),
263
+ ...optionalBooleanField(record, "runFullVerification", pathName),
264
+ };
265
+ }
266
+ function validateAgentConfig(value) {
267
+ if (value === undefined) {
268
+ return {};
269
+ }
270
+ const pathName = "project config.automation.agent";
271
+ const record = assertRecord(value, pathName);
272
+ const coordinatorProfileId = optionalNullableStringField(record, "coordinatorProfileId", pathName);
273
+ const profiles = optionalArrayField(record, "profiles", pathName, validateAgentProfileConfig);
274
+ if (profiles.profiles) {
275
+ assertUniqueAgentProfileIds(profiles.profiles, `${pathName}.profiles`);
276
+ }
277
+ if (coordinatorProfileId.coordinatorProfileId) {
278
+ const profile = profiles.profiles?.find((item) => item.id === coordinatorProfileId.coordinatorProfileId);
279
+ if (!profile) {
280
+ throw new NexusAutomationConfigError(`${pathName}.coordinatorProfileId must reference a configured agent profile`);
281
+ }
282
+ }
283
+ return {
284
+ ...optionalNullableStringField(record, "command", pathName),
285
+ ...optionalNullablePositiveIntegerField(record, "timeoutMs", pathName),
286
+ ...coordinatorProfileId,
287
+ ...optionalPositiveIntegerField(record, "maxConcurrentSubagents", pathName),
288
+ ...profiles,
289
+ ...validateAgentRelaunchConfig(record.relaunch),
290
+ };
291
+ }
292
+ function validateAgentProfileConfig(value, pathName) {
293
+ const record = assertRecord(value, pathName);
294
+ return {
295
+ id: requiredNonEmptyString(record.id, `${pathName}.id`),
296
+ executor: requiredNonEmptyString(record.executor, `${pathName}.executor`),
297
+ model: optionalNullableString(record.model, `${pathName}.model`) ?? null,
298
+ version: optionalNullableString(record.version, `${pathName}.version`) ?? null,
299
+ variant: optionalNullableString(record.variant, `${pathName}.variant`) ?? null,
300
+ reasoning: optionalNullableString(record.reasoning, `${pathName}.reasoning`) ?? null,
301
+ intelligence: optionalNullableString(record.intelligence, `${pathName}.intelligence`) ??
302
+ null,
303
+ intendedUse: validateAgentProfileIntendedUse(record.intendedUse, `${pathName}.intendedUse`),
304
+ safety: validateAgentProfileSafetyConfig(record.safety, `${pathName}.safety`),
305
+ command: optionalNullableString(record.command, `${pathName}.command`) ?? null,
306
+ args: optionalStringArray(record.args, `${pathName}.args`) ?? [],
307
+ };
308
+ }
309
+ function validateAgentProfileIntendedUse(value, pathName) {
310
+ if (value === undefined) {
311
+ return "any";
312
+ }
313
+ if (value === "any" || value === "coordinator" || value === "subagent") {
314
+ return value;
315
+ }
316
+ throw new NexusAutomationConfigError(`${pathName} must be any, coordinator, or subagent`);
317
+ }
318
+ function validateAgentProfileSafetyConfig(value, pathName) {
319
+ if (value === undefined || value === null) {
320
+ return null;
321
+ }
322
+ return {
323
+ ...defaultNexusAutomationConfig.safety,
324
+ ...validateSafetyConfigAt(value, pathName),
325
+ };
326
+ }
327
+ function assertUniqueAgentProfileIds(profiles, pathName) {
328
+ const ids = new Set();
329
+ for (const profile of profiles) {
330
+ if (ids.has(profile.id)) {
331
+ throw new NexusAutomationConfigError(`${pathName} contains duplicate id: ${profile.id}`);
332
+ }
333
+ ids.add(profile.id);
334
+ }
335
+ }
336
+ function validateAgentRelaunchConfig(value) {
337
+ if (value === undefined) {
338
+ return {};
339
+ }
340
+ const pathName = "project config.automation.agent.relaunch";
341
+ const record = assertRecord(value, pathName);
342
+ return {
343
+ relaunch: {
344
+ ...defaultNexusAutomationConfig.agent.relaunch,
345
+ ...optionalBooleanField(record, "whileEligible", pathName),
346
+ },
347
+ };
348
+ }
349
+ function validateTargetConfig(value) {
350
+ if (value === undefined) {
351
+ return {};
352
+ }
353
+ const pathName = "project config.automation.target";
354
+ const record = assertRecord(value, pathName);
355
+ return {
356
+ ...optionalNullableStringField(record, "id", pathName),
357
+ ...optionalNullableStringField(record, "objective", pathName),
358
+ ...optionalRelativePathField(record, "statePath", pathName),
359
+ ...optionalRelativePathField(record, "cycleLedgerPath", pathName),
360
+ ...optionalBooleanField(record, "stopWhenNoEligibleWork", pathName),
361
+ ...optionalNullablePositiveIntegerField(record, "maxCycles", pathName),
362
+ ...optionalNullablePositiveIntegerField(record, "maxWorkItems", pathName),
363
+ };
364
+ }
365
+ function validateDependencyLinkConfig(value, pathName) {
366
+ const record = assertRecord(value, pathName);
367
+ return {
368
+ source: requiredNonEmptyString(record.source, `${pathName}.source`),
369
+ target: requiredNonEmptyString(record.target, `${pathName}.target`),
370
+ required: optionalBoolean(record, "required", pathName) ?? false,
371
+ };
372
+ }
373
+ function validateSafetyConfig(value) {
374
+ return validateSafetyConfigAt(value, "project config.automation.safety");
375
+ }
376
+ function validateSafetyConfigAt(value, pathName) {
377
+ if (value === undefined) {
378
+ return {};
379
+ }
380
+ const record = assertRecord(value, pathName);
381
+ return {
382
+ ...optionalSafetyProfileField(record, "profile", pathName),
383
+ ...optionalBooleanField(record, "allowHostMutation", pathName),
384
+ ...optionalBooleanField(record, "allowDependencyInstall", pathName),
385
+ ...optionalBooleanField(record, "allowLiveServices", pathName),
386
+ };
387
+ }
388
+ function validatePublicationConfig(value) {
389
+ if (value === undefined) {
390
+ return {};
391
+ }
392
+ const pathName = "project config.automation.publication";
393
+ const record = assertRecord(value, pathName);
394
+ return {
395
+ ...optionalPublicationStrategyField(record, "strategy", pathName),
396
+ ...optionalNullableStringField(record, "remote", pathName),
397
+ ...optionalNullableStringField(record, "targetBranch", pathName),
398
+ ...optionalBooleanField(record, "push", pathName),
399
+ };
400
+ }
401
+ function assertRecord(value, pathName) {
402
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
403
+ throw new NexusAutomationConfigError(`${pathName} must be an object`);
404
+ }
405
+ return value;
406
+ }
407
+ function optionalBoolean(record, key, pathName) {
408
+ const value = record[key];
409
+ if (value === undefined) {
410
+ return undefined;
411
+ }
412
+ if (typeof value !== "boolean") {
413
+ throw new NexusAutomationConfigError(`${pathName}.${key} must be a boolean`);
414
+ }
415
+ return value;
416
+ }
417
+ function optionalBooleanField(record, key, pathName, outputKey = key) {
418
+ const value = optionalBoolean(record, key, pathName);
419
+ return value === undefined ? {} : { [outputKey]: value };
420
+ }
421
+ function optionalStringField(record, key, pathName) {
422
+ const value = record[key];
423
+ if (value === undefined) {
424
+ return {};
425
+ }
426
+ return {
427
+ [key]: requiredNonEmptyString(value, `${pathName}.${key}`),
428
+ };
429
+ }
430
+ function optionalNullableString(value, pathName) {
431
+ if (value === undefined) {
432
+ return undefined;
433
+ }
434
+ if (value === null) {
435
+ return null;
436
+ }
437
+ return requiredNonEmptyString(value, pathName);
438
+ }
439
+ function optionalNullableStringField(record, key, pathName) {
440
+ const value = record[key];
441
+ if (value === undefined) {
442
+ return {};
443
+ }
444
+ if (value === null) {
445
+ return { [key]: null };
446
+ }
447
+ return {
448
+ [key]: requiredNonEmptyString(value, `${pathName}.${key}`),
449
+ };
450
+ }
451
+ function optionalRelativePathField(record, key, pathName) {
452
+ const value = record[key];
453
+ if (value === undefined) {
454
+ return {};
455
+ }
456
+ const normalized = requiredNonEmptyString(value, `${pathName}.${key}`);
457
+ if (normalized.split(/[\\/]/u).some((part) => part === "..") ||
458
+ /^[A-Za-z]:/u.test(normalized) ||
459
+ normalized.startsWith("/") ||
460
+ normalized.startsWith("\\")) {
461
+ throw new NexusAutomationConfigError(`${pathName}.${key} must be a project-relative path`);
462
+ }
463
+ return { [key]: normalized };
464
+ }
465
+ function optionalPositiveIntegerField(record, key, pathName) {
466
+ const value = record[key];
467
+ if (value === undefined) {
468
+ return {};
469
+ }
470
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
471
+ throw new NexusAutomationConfigError(`${pathName}.${key} must be a positive integer`);
472
+ }
473
+ return { [key]: value };
474
+ }
475
+ function optionalNullablePositiveIntegerField(record, key, pathName) {
476
+ const value = record[key];
477
+ if (value === undefined) {
478
+ return {};
479
+ }
480
+ if (value === null) {
481
+ return { [key]: null };
482
+ }
483
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
484
+ throw new NexusAutomationConfigError(`${pathName}.${key} must be a positive integer or null`);
485
+ }
486
+ return { [key]: value };
487
+ }
488
+ function optionalArrayField(record, key, pathName, normalizeItem) {
489
+ const value = record[key];
490
+ if (value === undefined) {
491
+ return {};
492
+ }
493
+ if (!Array.isArray(value)) {
494
+ throw new NexusAutomationConfigError(`${pathName}.${key} must be an array`);
495
+ }
496
+ return {
497
+ [key]: value.map((item, index) => normalizeItem(item, `${pathName}.${key}[${index}]`)),
498
+ };
499
+ }
500
+ function optionalStringArray(value, pathName) {
501
+ if (value === undefined) {
502
+ return undefined;
503
+ }
504
+ if (!Array.isArray(value)) {
505
+ throw new NexusAutomationConfigError(`${pathName} must be an array`);
506
+ }
507
+ return value.map((item, index) => requiredNonEmptyString(item, `${pathName}[${index}]`));
508
+ }
509
+ function optionalSafetyProfileField(record, key, pathName) {
510
+ const value = record[key];
511
+ if (value === undefined) {
512
+ return {};
513
+ }
514
+ if (value === "local" || value === "isolated" || value === "host-authorized") {
515
+ return { [key]: value };
516
+ }
517
+ throw new NexusAutomationConfigError(`${pathName}.${key} must be local, isolated, or host-authorized`);
518
+ }
519
+ function optionalPublicationStrategyField(record, key, pathName) {
520
+ const value = record[key];
521
+ if (value === undefined) {
522
+ return {};
523
+ }
524
+ if (value === "local_only" ||
525
+ value === "direct_integration" ||
526
+ value === "review_handoff") {
527
+ return { [key]: value };
528
+ }
529
+ throw new NexusAutomationConfigError(`${pathName}.${key} must be local_only, direct_integration, or review_handoff`);
530
+ }
531
+ function validateWorkStatus(value, pathName) {
532
+ if (value === "todo" ||
533
+ value === "ready" ||
534
+ value === "in_progress" ||
535
+ value === "blocked" ||
536
+ value === "done" ||
537
+ value === "wont_do") {
538
+ return value;
539
+ }
540
+ throw new NexusAutomationConfigError(`${pathName} must be todo, ready, in_progress, blocked, done, or wont_do`);
541
+ }
542
+ function requiredNonEmptyString(value, pathName) {
543
+ if (typeof value !== "string" || value.trim().length === 0) {
544
+ throw new NexusAutomationConfigError(`${pathName} must be a non-empty string`);
545
+ }
546
+ return value.trim();
547
+ }
@@ -0,0 +1,37 @@
1
+ import type { NexusAutomationConfig } from "./nexusAutomationConfig.js";
2
+ import { type NexusProjectConfig } from "./nexusProjectConfig.js";
3
+ import { type ResolvedNexusProjectComponent } from "./nexusProjectLifecycle.js";
4
+ import { type CreateWorkTrackerProviderOptions } from "./workTrackingProviderService.js";
5
+ import type { WorkItem, WorkStatus, WorkTrackerProvider } from "./workTrackingTypes.js";
6
+ export interface EnqueueNexusAutomationWorkItemProviderContext {
7
+ projectRoot: string;
8
+ sourceRoot: string;
9
+ projectConfig: NexusProjectConfig;
10
+ component: ResolvedNexusProjectComponent;
11
+ workTracking: NonNullable<ResolvedNexusProjectComponent["workTracking"]>;
12
+ }
13
+ export type EnqueueNexusAutomationWorkItemProviderFactory = (context: EnqueueNexusAutomationWorkItemProviderContext) => WorkTrackerProvider;
14
+ export interface EnqueueNexusAutomationWorkItemOptions {
15
+ projectRoot: string;
16
+ title: string;
17
+ description?: string | null;
18
+ status?: WorkStatus;
19
+ labels?: string[];
20
+ assignees?: string[];
21
+ milestone?: string | null;
22
+ provider?: WorkTrackerProvider;
23
+ providerFactory?: EnqueueNexusAutomationWorkItemProviderFactory;
24
+ providerOptions?: Omit<CreateWorkTrackerProviderOptions, "projectRoot" | "now">;
25
+ now?: () => Date | string;
26
+ }
27
+ export interface EnqueueNexusAutomationWorkItemResult {
28
+ projectRoot: string;
29
+ sourceRoot: string;
30
+ projectConfig: NexusProjectConfig;
31
+ automationConfig: NexusAutomationConfig;
32
+ workItem: WorkItem;
33
+ }
34
+ export declare class NexusAutomationEnqueueError extends Error {
35
+ constructor(message: string);
36
+ }
37
+ export declare function enqueueNexusAutomationWorkItem(options: EnqueueNexusAutomationWorkItemOptions): Promise<EnqueueNexusAutomationWorkItemResult>;