@vfarcic/dot-ai 0.115.0 → 0.117.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 (143) hide show
  1. package/README.md +21 -18
  2. package/dist/core/ai-provider-factory.d.ts +4 -2
  3. package/dist/core/ai-provider-factory.d.ts.map +1 -1
  4. package/dist/core/ai-provider-factory.js +17 -6
  5. package/dist/core/capability-operations.js +1 -1
  6. package/dist/core/generic-session-manager.d.ts +67 -0
  7. package/dist/core/generic-session-manager.d.ts.map +1 -0
  8. package/dist/core/generic-session-manager.js +192 -0
  9. package/dist/core/pattern-operations.js +1 -1
  10. package/dist/core/providers/noop-provider.d.ts +47 -0
  11. package/dist/core/providers/noop-provider.d.ts.map +1 -0
  12. package/dist/core/providers/noop-provider.js +63 -0
  13. package/dist/core/schema.d.ts.map +1 -1
  14. package/dist/core/schema.js +13 -13
  15. package/dist/core/session-utils.d.ts +3 -6
  16. package/dist/core/session-utils.d.ts.map +1 -1
  17. package/dist/core/session-utils.js +5 -13
  18. package/dist/core/shared-prompt-loader.d.ts +15 -3
  19. package/dist/core/shared-prompt-loader.d.ts.map +1 -1
  20. package/dist/core/shared-prompt-loader.js +67 -14
  21. package/dist/core/unified-creation-session.d.ts +3 -10
  22. package/dist/core/unified-creation-session.d.ts.map +1 -1
  23. package/dist/core/unified-creation-session.js +34 -75
  24. package/dist/core/unified-creation-types.d.ts +31 -22
  25. package/dist/core/unified-creation-types.d.ts.map +1 -1
  26. package/dist/evaluation/eval-runner.js +12 -3
  27. package/dist/evaluation/evaluators/base-comparative.d.ts +2 -0
  28. package/dist/evaluation/evaluators/base-comparative.d.ts.map +1 -1
  29. package/dist/evaluation/evaluators/base-comparative.js +13 -1
  30. package/dist/evaluation/graph-generator.d.ts +56 -0
  31. package/dist/evaluation/graph-generator.d.ts.map +1 -0
  32. package/dist/evaluation/graph-generator.js +694 -0
  33. package/dist/evaluation/metadata-loader.d.ts +39 -0
  34. package/dist/evaluation/metadata-loader.d.ts.map +1 -0
  35. package/dist/evaluation/metadata-loader.js +74 -0
  36. package/dist/evaluation/platform-synthesizer.d.ts +5 -1
  37. package/dist/evaluation/platform-synthesizer.d.ts.map +1 -1
  38. package/dist/evaluation/platform-synthesizer.js +65 -23
  39. package/dist/evaluation/run-platform-synthesis.js +22 -5
  40. package/dist/interfaces/mcp.d.ts.map +1 -1
  41. package/dist/interfaces/mcp.js +9 -34
  42. package/dist/tools/answer-question.d.ts.map +1 -1
  43. package/dist/tools/answer-question.js +12 -12
  44. package/dist/tools/choose-solution.js +1 -1
  45. package/dist/tools/generate-manifests.d.ts.map +1 -1
  46. package/dist/tools/generate-manifests.js +9 -10
  47. package/dist/tools/index.d.ts +1 -1
  48. package/dist/tools/index.d.ts.map +1 -1
  49. package/dist/tools/index.js +6 -6
  50. package/dist/tools/organizational-data.js +12 -12
  51. package/dist/tools/project-setup/discovery.d.ts +15 -0
  52. package/dist/tools/project-setup/discovery.d.ts.map +1 -0
  53. package/dist/tools/project-setup/discovery.js +104 -0
  54. package/dist/tools/project-setup/generate-scope.d.ts +15 -0
  55. package/dist/tools/project-setup/generate-scope.d.ts.map +1 -0
  56. package/dist/tools/project-setup/generate-scope.js +237 -0
  57. package/dist/tools/project-setup/report-scan.d.ts +15 -0
  58. package/dist/tools/project-setup/report-scan.d.ts.map +1 -0
  59. package/dist/tools/project-setup/report-scan.js +156 -0
  60. package/dist/tools/project-setup/types.d.ts +111 -0
  61. package/dist/tools/project-setup/types.d.ts.map +1 -0
  62. package/dist/tools/project-setup/types.js +8 -0
  63. package/dist/tools/project-setup.d.ts +28 -0
  64. package/dist/tools/project-setup.d.ts.map +1 -0
  65. package/dist/tools/project-setup.js +134 -0
  66. package/dist/tools/recommend.js +1 -1
  67. package/dist/tools/remediate.js +1 -1
  68. package/dist/tools/version.d.ts +0 -7
  69. package/dist/tools/version.d.ts.map +1 -1
  70. package/dist/tools/version.js +5 -34
  71. package/package.json +4 -2
  72. package/prompts/capability-inference.md +2 -2
  73. package/prompts/infrastructure-trigger-expansion.md +2 -2
  74. package/prompts/intent-analysis.md +2 -2
  75. package/prompts/kyverno-generation.md +14 -14
  76. package/prompts/manifest-generation.md +5 -5
  77. package/prompts/map-intent-to-operation.md +2 -2
  78. package/prompts/pattern-complete-error.md +1 -1
  79. package/prompts/pattern-complete-success.md +4 -4
  80. package/prompts/pattern-rationale.md +1 -1
  81. package/prompts/pattern-resources.md +1 -1
  82. package/prompts/pattern-review.md +5 -5
  83. package/prompts/policy-complete-apply.md +4 -4
  84. package/prompts/policy-complete-discard.md +1 -1
  85. package/prompts/policy-complete-error.md +1 -1
  86. package/prompts/policy-complete-save.md +4 -4
  87. package/prompts/policy-complete-success.md +4 -4
  88. package/prompts/policy-namespace-scope.md +1 -1
  89. package/prompts/question-generation.md +5 -5
  90. package/prompts/resource-analysis.md +3 -3
  91. package/prompts/resource-selection.md +3 -3
  92. package/prompts/solution-enhancement.md +4 -4
  93. package/scripts/anthropic.nu +9 -13
  94. package/scripts/common.nu +31 -33
  95. package/scripts/ingress.nu +5 -4
  96. package/scripts/kubernetes.nu +38 -53
  97. package/dist/core/doc-discovery.d.ts +0 -38
  98. package/dist/core/doc-discovery.d.ts.map +0 -1
  99. package/dist/core/doc-discovery.js +0 -231
  100. package/dist/core/doc-testing-session.d.ts +0 -109
  101. package/dist/core/doc-testing-session.d.ts.map +0 -1
  102. package/dist/core/doc-testing-session.js +0 -696
  103. package/dist/core/doc-testing-types.d.ts +0 -127
  104. package/dist/core/doc-testing-types.d.ts.map +0 -1
  105. package/dist/core/doc-testing-types.js +0 -53
  106. package/dist/core/nushell-runtime.d.ts +0 -39
  107. package/dist/core/nushell-runtime.d.ts.map +0 -1
  108. package/dist/core/nushell-runtime.js +0 -103
  109. package/dist/core/platform-operations.d.ts +0 -70
  110. package/dist/core/platform-operations.d.ts.map +0 -1
  111. package/dist/core/platform-operations.js +0 -294
  112. package/dist/tools/build-platform.d.ts +0 -25
  113. package/dist/tools/build-platform.d.ts.map +0 -1
  114. package/dist/tools/build-platform.js +0 -277
  115. package/dist/tools/test-docs.d.ts +0 -22
  116. package/dist/tools/test-docs.d.ts.map +0 -1
  117. package/dist/tools/test-docs.js +0 -351
  118. package/prompts/doc-testing-done.md +0 -51
  119. package/prompts/doc-testing-fix.md +0 -120
  120. package/prompts/doc-testing-scan.md +0 -140
  121. package/prompts/doc-testing-test-section.md +0 -169
  122. package/prompts/platform-operations-parse-script-help.md +0 -68
  123. package/scripts/ack.nu +0 -195
  124. package/scripts/argo-workflows.nu +0 -47
  125. package/scripts/argocd.nu +0 -85
  126. package/scripts/aso.nu +0 -74
  127. package/scripts/backstage.nu +0 -349
  128. package/scripts/cert-manager.nu +0 -13
  129. package/scripts/cnpg.nu +0 -14
  130. package/scripts/dot.nu +0 -32
  131. package/scripts/external-secrets.nu +0 -110
  132. package/scripts/gatekeeper.nu +0 -19
  133. package/scripts/github.nu +0 -42
  134. package/scripts/image.nu +0 -67
  135. package/scripts/kro.nu +0 -11
  136. package/scripts/kubevela.nu +0 -22
  137. package/scripts/port.nu +0 -71
  138. package/scripts/prometheus.nu +0 -21
  139. package/scripts/registry.nu +0 -55
  140. package/scripts/storage.nu +0 -210
  141. package/scripts/tests.nu +0 -12
  142. package/scripts/velero.nu +0 -45
  143. package/shared-prompts/validate-docs.md +0 -22
@@ -246,8 +246,8 @@ function parseNumericResponse(response, validOptions) {
246
246
  /**
247
247
  * Get session file path following established pattern
248
248
  */
249
- function getCapabilitySessionPath(sessionId, args) {
250
- const sessionDir = (0, session_utils_1.getAndValidateSessionDirectory)(args, false);
249
+ function getCapabilitySessionPath(sessionId) {
250
+ const sessionDir = (0, session_utils_1.getAndValidateSessionDirectory)(false);
251
251
  const sessionSubDir = path.join(sessionDir, 'capability-sessions');
252
252
  // Ensure capability-sessions subdirectory exists
253
253
  if (!fs.existsSync(sessionSubDir)) {
@@ -258,9 +258,9 @@ function getCapabilitySessionPath(sessionId, args) {
258
258
  /**
259
259
  * Load session from file system following established pattern
260
260
  */
261
- function loadCapabilitySession(sessionId, args) {
261
+ function loadCapabilitySession(sessionId) {
262
262
  try {
263
- const sessionPath = getCapabilitySessionPath(sessionId, args);
263
+ const sessionPath = getCapabilitySessionPath(sessionId);
264
264
  if (!fs.existsSync(sessionPath)) {
265
265
  return null;
266
266
  }
@@ -268,7 +268,7 @@ function loadCapabilitySession(sessionId, args) {
268
268
  const session = JSON.parse(sessionData);
269
269
  // Update last activity
270
270
  session.lastActivity = new Date().toISOString();
271
- saveCapabilitySession(session, args);
271
+ saveCapabilitySession(session);
272
272
  return session;
273
273
  }
274
274
  catch (error) {
@@ -279,9 +279,9 @@ function loadCapabilitySession(sessionId, args) {
279
279
  /**
280
280
  * Save session to file system following established pattern
281
281
  */
282
- function saveCapabilitySession(session, args) {
282
+ function saveCapabilitySession(session) {
283
283
  try {
284
- const sessionPath = getCapabilitySessionPath(session.sessionId, args);
284
+ const sessionPath = getCapabilitySessionPath(session.sessionId);
285
285
  fs.writeFileSync(sessionPath, JSON.stringify(session, null, 2), 'utf8');
286
286
  }
287
287
  catch (error) {
@@ -294,7 +294,7 @@ function saveCapabilitySession(session, args) {
294
294
  */
295
295
  function getOrCreateCapabilitySession(sessionId, args, logger, requestId) {
296
296
  if (sessionId) {
297
- const existing = loadCapabilitySession(sessionId, args);
297
+ const existing = loadCapabilitySession(sessionId);
298
298
  if (existing) {
299
299
  logger.info('Loaded existing capability session', {
300
300
  requestId,
@@ -312,7 +312,7 @@ function getOrCreateCapabilitySession(sessionId, args, logger, requestId) {
312
312
  startedAt: new Date().toISOString(),
313
313
  lastActivity: new Date().toISOString()
314
314
  };
315
- saveCapabilitySession(session, args);
315
+ saveCapabilitySession(session);
316
316
  logger.info('Created new capability session', {
317
317
  requestId,
318
318
  sessionId: newSessionId,
@@ -341,20 +341,20 @@ function validateCapabilityStep(session, clientStep) {
341
341
  /**
342
342
  * Transition session to next step with proper state updates
343
343
  */
344
- function transitionCapabilitySession(session, nextStep, updates, args) {
344
+ function transitionCapabilitySession(session, nextStep, updates) {
345
345
  session.currentStep = nextStep;
346
346
  session.lastActivity = new Date().toISOString();
347
347
  if (updates) {
348
348
  Object.assign(session, updates);
349
349
  }
350
- saveCapabilitySession(session, args);
350
+ saveCapabilitySession(session);
351
351
  }
352
352
  /**
353
353
  * Clean up session file after successful completion
354
354
  */
355
355
  function cleanupCapabilitySession(session, args, logger, requestId) {
356
356
  try {
357
- const sessionPath = getCapabilitySessionPath(session.sessionId, args);
357
+ const sessionPath = getCapabilitySessionPath(session.sessionId);
358
358
  if (fs.existsSync(sessionPath)) {
359
359
  fs.unlinkSync(sessionPath);
360
360
  logger.info('Capability session cleaned up after completion', {
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Discovery Handler - Project Setup Tool
3
+ * PRD #177 - Milestone 1: Core Tool Infrastructure
4
+ *
5
+ * Step 1 of workflow: Return list of files for client to scan
6
+ */
7
+ import { Logger } from '../../core/error-handling';
8
+ import { DiscoveryResponse } from './types';
9
+ /**
10
+ * Handle discovery stage - Step 1 of project setup workflow
11
+ *
12
+ * Loads ALL files from ALL scopes and returns for client to scan
13
+ */
14
+ export declare function handleDiscovery(logger: Logger, requestId: string): Promise<DiscoveryResponse>;
15
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/tools/project-setup/discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAgB,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EAAE,iBAAiB,EAAqC,MAAM,SAAS,CAAC;AAkB/E;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,iBAAiB,CAAC,CAiE5B"}
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ /**
3
+ * Discovery Handler - Project Setup Tool
4
+ * PRD #177 - Milestone 1: Core Tool Infrastructure
5
+ *
6
+ * Step 1 of workflow: Return list of files for client to scan
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.handleDiscovery = handleDiscovery;
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const error_handling_1 = require("../../core/error-handling");
46
+ const generic_session_manager_1 = require("../../core/generic-session-manager");
47
+ /**
48
+ * Handle discovery stage - Step 1 of project setup workflow
49
+ *
50
+ * Loads ALL files from ALL scopes and returns for client to scan
51
+ */
52
+ async function handleDiscovery(logger, requestId) {
53
+ return await error_handling_1.ErrorHandler.withErrorHandling(async () => {
54
+ logger.debug('Starting project setup discovery', { requestId });
55
+ // Load discovery config from source directory
56
+ // From dist/tools/project-setup/ -> ../../../ gets to project root, then src/tools/project-setup/
57
+ const configPath = path.join(__dirname, '..', '..', '..', 'src', 'tools', 'project-setup', 'discovery-config.json');
58
+ const configContent = fs.readFileSync(configPath, 'utf8');
59
+ const allConfig = JSON.parse(configContent);
60
+ // Collect all files from all scopes
61
+ const allFiles = [];
62
+ const scopeNames = Object.keys(allConfig);
63
+ for (const scopeName of scopeNames) {
64
+ const scopeConfig = allConfig[scopeName];
65
+ allFiles.push(...scopeConfig.files);
66
+ }
67
+ // Remove duplicates
68
+ const uniqueFiles = Array.from(new Set(allFiles));
69
+ // Initialize session manager with 'proj' prefix
70
+ const sessionManager = new generic_session_manager_1.GenericSessionManager('proj');
71
+ // Create new session with ALL scope configurations
72
+ const session = sessionManager.createSession({
73
+ currentStep: 'discover',
74
+ allScopes: allConfig, // Store all scope configurations
75
+ filesToCheck: uniqueFiles
76
+ });
77
+ logger.info('Project setup session created', {
78
+ requestId,
79
+ sessionId: session.sessionId,
80
+ scopeCount: scopeNames.length,
81
+ fileCount: uniqueFiles.length
82
+ });
83
+ // Return discovery response
84
+ const response = {
85
+ success: true,
86
+ sessionId: session.sessionId,
87
+ filesToCheck: uniqueFiles,
88
+ availableScopes: scopeNames,
89
+ nextStep: 'reportScan',
90
+ instructions: `Scan the repository for these files: ${uniqueFiles.join(', ')}. Check which files exist and build an array of those files. Then call projectSetup tool with step: "reportScan", sessionId: "${session.sessionId}", and existingFiles: [array of files that exist in the repository].`
91
+ };
92
+ logger.debug('Discovery response prepared', {
93
+ requestId,
94
+ sessionId: session.sessionId,
95
+ fileCount: response.filesToCheck.length,
96
+ scopes: scopeNames
97
+ });
98
+ return response;
99
+ }, {
100
+ operation: 'project_setup_discovery',
101
+ component: 'ProjectSetupTool',
102
+ requestId
103
+ });
104
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Generate Scope Handler - Project Setup Tool
3
+ * PRD #177 - Scope-based workflow refactoring
4
+ *
5
+ * Step 3 of workflow: Generate ALL files in a scope at once
6
+ */
7
+ import { Logger } from '../../core/error-handling';
8
+ import { GenerateScopeResponse, ErrorResponse } from './types';
9
+ /**
10
+ * Handle generateScope stage - Step 3 of project setup workflow
11
+ *
12
+ * Generates ALL files for a scope at once based on user answers
13
+ */
14
+ export declare function handleGenerateScope(sessionId: string, scope: string | undefined, answers: Record<string, any> | undefined, logger: Logger, requestId: string): Promise<GenerateScopeResponse | ErrorResponse>;
15
+ //# sourceMappingURL=generate-scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-scope.d.ts","sourceRoot":"","sources":["../../../src/tools/project-setup/generate-scope.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAgB,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EAAE,qBAAqB,EAA2B,aAAa,EAAiB,MAAM,SAAS,CAAC;AAGvG;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,EACxC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,GAAG,aAAa,CAAC,CA8JhD"}
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ /**
3
+ * Generate Scope Handler - Project Setup Tool
4
+ * PRD #177 - Scope-based workflow refactoring
5
+ *
6
+ * Step 3 of workflow: Generate ALL files in a scope at once
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleGenerateScope = handleGenerateScope;
10
+ const error_handling_1 = require("../../core/error-handling");
11
+ const generic_session_manager_1 = require("../../core/generic-session-manager");
12
+ const shared_prompt_loader_1 = require("../../core/shared-prompt-loader");
13
+ /**
14
+ * Handle generateScope stage - Step 3 of project setup workflow
15
+ *
16
+ * Generates ALL files for a scope at once based on user answers
17
+ */
18
+ async function handleGenerateScope(sessionId, scope, answers, logger, requestId) {
19
+ return await error_handling_1.ErrorHandler.withErrorHandling(async () => {
20
+ logger.debug('Starting scope generation', { requestId, sessionId, scope });
21
+ // Initialize session manager
22
+ const sessionManager = new generic_session_manager_1.GenericSessionManager('proj');
23
+ // Load session
24
+ const session = sessionManager.getSession(sessionId);
25
+ if (!session) {
26
+ return {
27
+ success: false,
28
+ error: {
29
+ message: `Session ${sessionId} not found`,
30
+ details: 'Please start a new session with step: "discover"'
31
+ }
32
+ };
33
+ }
34
+ // Validate inputs
35
+ if (!scope) {
36
+ return {
37
+ success: false,
38
+ error: {
39
+ message: 'scope is required for generateScope step',
40
+ details: 'Provide the scope name (e.g., "github-community")'
41
+ }
42
+ };
43
+ }
44
+ if (!answers) {
45
+ return {
46
+ success: false,
47
+ error: {
48
+ message: 'answers are required for generateScope step',
49
+ details: 'Provide answers to the questions for this scope'
50
+ }
51
+ };
52
+ }
53
+ // Validate session state
54
+ if (!session.data.allScopes || !session.data.existingFiles) {
55
+ return {
56
+ success: false,
57
+ error: {
58
+ message: 'Invalid session state',
59
+ details: 'Session does not contain required data'
60
+ }
61
+ };
62
+ }
63
+ const scopeConfig = session.data.allScopes[scope];
64
+ if (!scopeConfig) {
65
+ return {
66
+ success: false,
67
+ error: {
68
+ message: `Invalid scope: ${scope}`,
69
+ details: `Available scopes: ${Object.keys(session.data.allScopes).join(', ')}`
70
+ }
71
+ };
72
+ }
73
+ // Get files to generate (excluding existing ones)
74
+ const existingFiles = session.data.existingFiles;
75
+ const baseFiles = scopeConfig.files.filter(file => !existingFiles.includes(file));
76
+ // Add conditional-only files (files that exist ONLY in conditionalFiles, not in main files array)
77
+ const conditionalFiles = scopeConfig.conditionalFiles || {};
78
+ const conditionalOnlyFiles = Object.keys(conditionalFiles).filter(file => !scopeConfig.files.includes(file) && !existingFiles.includes(file));
79
+ // Combine base files and conditional-only files
80
+ const filesToGenerate = [...baseFiles, ...conditionalOnlyFiles];
81
+ // Evaluate conditional files and generate content
82
+ const generatedFiles = [];
83
+ const excludedFiles = [];
84
+ for (const fileName of filesToGenerate) {
85
+ // Check if this file has conditional generation rules
86
+ const conditionalRule = conditionalFiles[fileName];
87
+ if (conditionalRule) {
88
+ const shouldGenerate = evaluateCondition(conditionalRule.condition, answers);
89
+ if (!shouldGenerate) {
90
+ logger.info('File excluded due to conditional rule', {
91
+ requestId,
92
+ fileName,
93
+ scope,
94
+ condition: conditionalRule.condition,
95
+ reason: conditionalRule.reason
96
+ });
97
+ excludedFiles.push(fileName);
98
+ continue;
99
+ }
100
+ }
101
+ // Preprocess answers for template (convert comma-separated strings to arrays)
102
+ const processedAnswers = preprocessAnswers(answers);
103
+ // Generate file content
104
+ const content = generateFileContent(fileName, processedAnswers, logger);
105
+ generatedFiles.push({
106
+ path: fileName,
107
+ content,
108
+ reason: conditionalRule ? conditionalRule.reason : undefined
109
+ });
110
+ logger.info('File generated', {
111
+ requestId,
112
+ sessionId,
113
+ fileName,
114
+ scope,
115
+ contentLength: content.length
116
+ });
117
+ }
118
+ // Update session
119
+ session.data.currentStep = 'complete';
120
+ sessionManager.updateSession(sessionId, session.data);
121
+ logger.info('Scope generation complete', {
122
+ requestId,
123
+ sessionId,
124
+ scope,
125
+ generatedCount: generatedFiles.length,
126
+ excludedCount: excludedFiles.length
127
+ });
128
+ // Process additionalInstructions template if present
129
+ let additionalInstructions;
130
+ if (scopeConfig.additionalInstructions) {
131
+ additionalInstructions = replaceTemplateVariables(scopeConfig.additionalInstructions, answers);
132
+ }
133
+ return {
134
+ success: true,
135
+ sessionId,
136
+ scope,
137
+ files: generatedFiles,
138
+ excludedFiles: excludedFiles.length > 0 ? excludedFiles : undefined,
139
+ instructions: `Generated ${generatedFiles.length} file(s) for scope "${scope}".\n\n` +
140
+ `Files:\n${generatedFiles.map(f => `- ${f.path}`).join('\n')}\n\n` +
141
+ (excludedFiles.length > 0 ? `Excluded ${excludedFiles.length} file(s):\n${excludedFiles.map(f => `- ${f}`).join('\n')}\n\n` : '') +
142
+ `Write these files to your repository using the Write tool.`,
143
+ additionalInstructions
144
+ };
145
+ }, {
146
+ operation: 'project_setup_generate_scope',
147
+ component: 'ProjectSetupTool',
148
+ requestId
149
+ });
150
+ }
151
+ /**
152
+ * Generate file content from template using Handlebars
153
+ */
154
+ function generateFileContent(fileName, answers, logger) {
155
+ try {
156
+ // Load template using shared prompt loader with Handlebars support
157
+ // Templates use .hbs extension (e.g., README.md -> README.md.hbs)
158
+ const content = (0, shared_prompt_loader_1.loadPrompt)(fileName, answers, 'src/tools/project-setup/templates', '.hbs' // Add .hbs extension to template files
159
+ );
160
+ return content;
161
+ }
162
+ catch (error) {
163
+ logger.error('Failed to generate file content', error, { fileName });
164
+ return `# ${fileName}\n\nError: Could not generate content for this file.\nTemplate may be missing at: src/tools/project-setup/templates/${fileName}.hbs\n`;
165
+ }
166
+ }
167
+ /**
168
+ * Evaluate conditional file generation rule
169
+ *
170
+ * Supports conditions:
171
+ * - "false" -> always false
172
+ * - "true" -> always true
173
+ * - "variableName === 'value'" -> check if answers[variableName] === 'value'
174
+ * - "variableName === true" -> check if answers[variableName] is boolean true or truthy string
175
+ * - OR conditions: "condition1 || condition2 || condition3"
176
+ */
177
+ function evaluateCondition(condition, answers) {
178
+ const trimmed = condition.trim();
179
+ // Handle literal boolean strings
180
+ if (trimmed === 'false')
181
+ return false;
182
+ if (trimmed === 'true')
183
+ return true;
184
+ // Handle OR conditions: split by || and evaluate each part
185
+ if (trimmed.includes('||')) {
186
+ const conditions = trimmed.split('||').map(c => c.trim());
187
+ return conditions.some(cond => evaluateCondition(cond, answers));
188
+ }
189
+ // Handle equality checks with boolean: "variableName === true"
190
+ const booleanMatch = trimmed.match(/^(\w+)\s*===\s*(true|false)$/);
191
+ if (booleanMatch) {
192
+ const [, variableName, expectedValue] = booleanMatch;
193
+ const actualValue = answers[variableName];
194
+ // Check for truthy values: boolean true, string "yes", string "true"
195
+ if (expectedValue === 'true') {
196
+ return actualValue === true || actualValue === 'true' || actualValue === 'yes';
197
+ }
198
+ // Check for falsy values
199
+ return actualValue === false || actualValue === 'false' || actualValue === 'no';
200
+ }
201
+ // Handle equality checks with strings: "variableName === 'value'"
202
+ const stringMatch = trimmed.match(/^(\w+)\s*===\s*['"]([^'"]+)['"]$/);
203
+ if (stringMatch) {
204
+ const [, variableName, expectedValue] = stringMatch;
205
+ return answers[variableName] === expectedValue;
206
+ }
207
+ // Unknown condition format - default to false for safety
208
+ return false;
209
+ }
210
+ /**
211
+ * Preprocess answers for Handlebars templates
212
+ * Converts comma-separated strings to arrays where needed
213
+ */
214
+ function preprocessAnswers(answers) {
215
+ const processed = { ...answers };
216
+ // Convert maintainerUsernames from comma-separated string to array
217
+ if (processed.maintainerUsernames && typeof processed.maintainerUsernames === 'string') {
218
+ processed.maintainerUsernames = processed.maintainerUsernames
219
+ .split(',')
220
+ .map((username) => username.trim())
221
+ .filter((username) => username.length > 0);
222
+ }
223
+ return processed;
224
+ }
225
+ /**
226
+ * Replace template variables in additionalInstructions
227
+ * Simple replacement for {{variableName}} patterns
228
+ */
229
+ function replaceTemplateVariables(template, answers) {
230
+ let result = template;
231
+ // Replace all {{variableName}} with actual values
232
+ for (const [key, value] of Object.entries(answers)) {
233
+ const pattern = new RegExp(`\\{\\{${key}\\}\\}`, 'g');
234
+ result = result.replace(pattern, String(value || ''));
235
+ }
236
+ return result;
237
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Report Scan Handler - Project Setup Tool
3
+ * PRD #177 - Scope-based workflow refactoring
4
+ *
5
+ * Step 2 of workflow: Return ALL questions for selected scope
6
+ */
7
+ import { Logger } from '../../core/error-handling';
8
+ import { ReportScanResponse, ErrorResponse } from './types';
9
+ /**
10
+ * Handle reportScan stage - Step 2 of project setup workflow
11
+ *
12
+ * Returns all questions for the selected scope and list of files to generate
13
+ */
14
+ export declare function handleReportScan(sessionId: string, existingFiles: string[] | undefined, selectedScopes: string[] | undefined, logger: Logger, requestId: string): Promise<ReportScanResponse | ErrorResponse>;
15
+ //# sourceMappingURL=report-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report-scan.d.ts","sourceRoot":"","sources":["../../../src/tools/project-setup/report-scan.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAgB,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EAAE,kBAAkB,EAA2B,aAAa,EAAE,MAAM,SAAS,CAAC;AAErF;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EAAE,GAAG,SAAS,EACnC,cAAc,EAAE,MAAM,EAAE,GAAG,SAAS,EACpC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,GAAG,aAAa,CAAC,CA4I7C"}
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ /**
3
+ * Report Scan Handler - Project Setup Tool
4
+ * PRD #177 - Scope-based workflow refactoring
5
+ *
6
+ * Step 2 of workflow: Return ALL questions for selected scope
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleReportScan = handleReportScan;
10
+ const error_handling_1 = require("../../core/error-handling");
11
+ const generic_session_manager_1 = require("../../core/generic-session-manager");
12
+ /**
13
+ * Handle reportScan stage - Step 2 of project setup workflow
14
+ *
15
+ * Returns all questions for the selected scope and list of files to generate
16
+ */
17
+ async function handleReportScan(sessionId, existingFiles, selectedScopes, logger, requestId) {
18
+ return await error_handling_1.ErrorHandler.withErrorHandling(async () => {
19
+ logger.debug('Starting report scan analysis', { requestId, sessionId });
20
+ // Initialize session manager
21
+ const sessionManager = new generic_session_manager_1.GenericSessionManager('proj');
22
+ // Load session
23
+ const session = sessionManager.getSession(sessionId);
24
+ if (!session) {
25
+ return {
26
+ success: false,
27
+ error: {
28
+ message: `Session ${sessionId} not found`,
29
+ details: 'Please start a new session with step: "discover"'
30
+ }
31
+ };
32
+ }
33
+ // Validate session state
34
+ if (!session.data.allScopes || !session.data.filesToCheck) {
35
+ return {
36
+ success: false,
37
+ error: {
38
+ message: 'Invalid session state',
39
+ details: 'Session does not contain scope configuration data'
40
+ }
41
+ };
42
+ }
43
+ const allScopes = session.data.allScopes;
44
+ // Store or retrieve existingFiles
45
+ let filesToUse;
46
+ if (existingFiles !== undefined) {
47
+ filesToUse = existingFiles;
48
+ session.data.existingFiles = existingFiles;
49
+ sessionManager.updateSession(sessionId, session.data);
50
+ logger.debug('Stored existingFiles in session', { requestId, sessionId, count: existingFiles.length });
51
+ }
52
+ else if (session.data.existingFiles !== undefined) {
53
+ filesToUse = session.data.existingFiles;
54
+ logger.debug('Reusing existingFiles from session', { requestId, sessionId, count: filesToUse.length });
55
+ }
56
+ else {
57
+ return {
58
+ success: false,
59
+ error: {
60
+ message: 'existingFiles is required for first reportScan call',
61
+ details: 'Please provide an array of files that exist in the repository'
62
+ }
63
+ };
64
+ }
65
+ // If no scopes selected, return analysis report
66
+ if (!selectedScopes || selectedScopes.length === 0) {
67
+ // Analyze scope completeness
68
+ const scopeStatus = {};
69
+ for (const [scopeName, scopeConfig] of Object.entries(allScopes)) {
70
+ const missingFiles = scopeConfig.files.filter(file => !filesToUse.includes(file));
71
+ scopeStatus[scopeName] = {
72
+ complete: missingFiles.length === 0,
73
+ missingFiles
74
+ };
75
+ }
76
+ const incompleteScopes = Object.entries(scopeStatus)
77
+ .filter(([_, status]) => !status.complete)
78
+ .map(([scopeName, _]) => scopeName);
79
+ // Generate report for user to review
80
+ const report = generateReport(scopeStatus, allScopes);
81
+ logger.info('Generated scope analysis report', {
82
+ requestId,
83
+ sessionId,
84
+ totalScopes: Object.keys(allScopes).length,
85
+ incompleteScopes: incompleteScopes.length
86
+ });
87
+ const incompleteScopeNames = incompleteScopes.join('", "');
88
+ return {
89
+ success: true,
90
+ sessionId,
91
+ nextStep: 'generateScope',
92
+ scope: '',
93
+ questions: [],
94
+ filesToGenerate: [],
95
+ instructions: `${report}\n\nIncomplete scopes: ${incompleteScopes.join(', ')}\n\n**IMPORTANT**: Present each scope individually to the user. Do NOT combine or group scopes. Use exact scope names.\n\nTo proceed, call projectSetup tool again with:\n- step: "reportScan"\n- sessionId: "${sessionId}"\n- selectedScopes: ["${incompleteScopeNames}"] (Use exact scope names from the list above)`
96
+ };
97
+ }
98
+ // User selected scope(s) - take first scope to generate
99
+ const selectedScope = selectedScopes[0];
100
+ const scopeConfig = allScopes[selectedScope];
101
+ if (!scopeConfig) {
102
+ return {
103
+ success: false,
104
+ error: {
105
+ message: `Invalid scope: ${selectedScope}`,
106
+ details: `Available scopes: ${Object.keys(allScopes).join(', ')}`
107
+ }
108
+ };
109
+ }
110
+ // Calculate which files need to be generated
111
+ const filesToGenerate = scopeConfig.files.filter(file => !filesToUse.includes(file));
112
+ // Store selected scopes in session
113
+ session.data.selectedScopes = selectedScopes;
114
+ session.data.currentStep = 'generateScope';
115
+ sessionManager.updateSession(sessionId, session.data);
116
+ logger.info('Ready to generate scope', {
117
+ requestId,
118
+ sessionId,
119
+ scope: selectedScope,
120
+ filesToGenerate: filesToGenerate.length,
121
+ questions: scopeConfig.questions.length
122
+ });
123
+ // Return ALL questions for this scope
124
+ return {
125
+ success: true,
126
+ sessionId,
127
+ nextStep: 'generateScope',
128
+ scope: selectedScope,
129
+ questions: scopeConfig.questions,
130
+ filesToGenerate,
131
+ instructions: `Scope: ${selectedScope}\n\nFiles to generate (${filesToGenerate.length}):\n${filesToGenerate.map(f => `- ${f}`).join('\n')}\n\nQuestions (${scopeConfig.questions.length}):\n${scopeConfig.questions.map((q, i) => `${i + 1}. ${q.question} (ID: ${q.id}${q.required ? ', required' : ''})`).join('\n')}\n\nAnalyze the repository to determine answers for these questions. Present your suggested answers as a numbered list. Once finalized, call projectSetup tool with:\n- step: "generateScope"\n- sessionId: "${sessionId}"\n- scope: "${selectedScope}"\n- answers: {${scopeConfig.questions.slice(0, 2).map(q => `"${q.id}": "value"`).join(', ')}, ...}`
132
+ };
133
+ }, {
134
+ operation: 'project_setup_report_scan',
135
+ component: 'ProjectSetupTool',
136
+ requestId
137
+ });
138
+ }
139
+ /**
140
+ * Generate human-readable report of scope analysis
141
+ */
142
+ function generateReport(scopeStatus, allScopes) {
143
+ const lines = ['Repository Analysis:', ''];
144
+ for (const [scopeName, status] of Object.entries(scopeStatus)) {
145
+ const scopeConfig = allScopes[scopeName];
146
+ const totalFiles = scopeConfig.files.length;
147
+ const missingCount = status.missingFiles.length;
148
+ const existingCount = totalFiles - missingCount;
149
+ const statusIcon = status.complete ? '✓' : '○';
150
+ lines.push(`${statusIcon} ${scopeName}: ${existingCount}/${totalFiles} files exist`);
151
+ if (!status.complete) {
152
+ lines.push(` Missing: ${status.missingFiles.join(', ')}`);
153
+ }
154
+ }
155
+ return lines.join('\n');
156
+ }