decibel-tools-mcp 1.0.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/LICENSE +21 -0
- package/README.md +335 -0
- package/dist/agentic/compiler.d.ts +21 -0
- package/dist/agentic/compiler.d.ts.map +1 -0
- package/dist/agentic/compiler.js +267 -0
- package/dist/agentic/compiler.js.map +1 -0
- package/dist/agentic/golden.d.ts +25 -0
- package/dist/agentic/golden.d.ts.map +1 -0
- package/dist/agentic/golden.js +255 -0
- package/dist/agentic/golden.js.map +1 -0
- package/dist/agentic/index.d.ts +17 -0
- package/dist/agentic/index.d.ts.map +1 -0
- package/dist/agentic/index.js +153 -0
- package/dist/agentic/index.js.map +1 -0
- package/dist/agentic/linter.d.ts +20 -0
- package/dist/agentic/linter.d.ts.map +1 -0
- package/dist/agentic/linter.js +340 -0
- package/dist/agentic/linter.js.map +1 -0
- package/dist/agentic/renderer.d.ts +17 -0
- package/dist/agentic/renderer.d.ts.map +1 -0
- package/dist/agentic/renderer.js +277 -0
- package/dist/agentic/renderer.js.map +1 -0
- package/dist/agentic/types.d.ts +199 -0
- package/dist/agentic/types.d.ts.map +1 -0
- package/dist/agentic/types.js +8 -0
- package/dist/agentic/types.js.map +1 -0
- package/dist/architectAdrs.d.ts +19 -0
- package/dist/architectAdrs.d.ts.map +1 -0
- package/dist/architectAdrs.js +123 -0
- package/dist/architectAdrs.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +19 -0
- package/dist/config.js.map +1 -0
- package/dist/dataRoot.d.ts +45 -0
- package/dist/dataRoot.d.ts.map +1 -0
- package/dist/dataRoot.js +201 -0
- package/dist/dataRoot.js.map +1 -0
- package/dist/decibelPaths.d.ts +42 -0
- package/dist/decibelPaths.d.ts.map +1 -0
- package/dist/decibelPaths.js +150 -0
- package/dist/decibelPaths.js.map +1 -0
- package/dist/httpServer.d.ts +49 -0
- package/dist/httpServer.d.ts.map +1 -0
- package/dist/httpServer.js +1472 -0
- package/dist/httpServer.js.map +1 -0
- package/dist/lib/benchmark.d.ts +110 -0
- package/dist/lib/benchmark.d.ts.map +1 -0
- package/dist/lib/benchmark.js +338 -0
- package/dist/lib/benchmark.js.map +1 -0
- package/dist/lib/supabase.d.ts +123 -0
- package/dist/lib/supabase.d.ts.map +1 -0
- package/dist/lib/supabase.js +91 -0
- package/dist/lib/supabase.js.map +1 -0
- package/dist/projectPaths.d.ts +27 -0
- package/dist/projectPaths.d.ts.map +1 -0
- package/dist/projectPaths.js +86 -0
- package/dist/projectPaths.js.map +1 -0
- package/dist/projectRegistry.d.ts +97 -0
- package/dist/projectRegistry.d.ts.map +1 -0
- package/dist/projectRegistry.js +362 -0
- package/dist/projectRegistry.js.map +1 -0
- package/dist/sentinelIssues.d.ts +44 -0
- package/dist/sentinelIssues.d.ts.map +1 -0
- package/dist/sentinelIssues.js +213 -0
- package/dist/sentinelIssues.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +93 -0
- package/dist/server.js.map +1 -0
- package/dist/test.d.ts +7 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +77 -0
- package/dist/test.js.map +1 -0
- package/dist/tools/agentic/index.d.ts +7 -0
- package/dist/tools/agentic/index.d.ts.map +1 -0
- package/dist/tools/agentic/index.js +180 -0
- package/dist/tools/agentic/index.js.map +1 -0
- package/dist/tools/architect/index.d.ts +9 -0
- package/dist/tools/architect/index.d.ts.map +1 -0
- package/dist/tools/architect/index.js +383 -0
- package/dist/tools/architect/index.js.map +1 -0
- package/dist/tools/architect.d.ts +19 -0
- package/dist/tools/architect.d.ts.map +1 -0
- package/dist/tools/architect.js +88 -0
- package/dist/tools/architect.js.map +1 -0
- package/dist/tools/bench.d.ts +89 -0
- package/dist/tools/bench.d.ts.map +1 -0
- package/dist/tools/bench.js +826 -0
- package/dist/tools/bench.js.map +1 -0
- package/dist/tools/context/index.d.ts +11 -0
- package/dist/tools/context/index.d.ts.map +1 -0
- package/dist/tools/context/index.js +439 -0
- package/dist/tools/context/index.js.map +1 -0
- package/dist/tools/context.d.ts +146 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +481 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/crit.d.ts +63 -0
- package/dist/tools/crit.d.ts.map +1 -0
- package/dist/tools/crit.js +159 -0
- package/dist/tools/crit.js.map +1 -0
- package/dist/tools/data-inspector.d.ts +188 -0
- package/dist/tools/data-inspector.d.ts.map +1 -0
- package/dist/tools/data-inspector.js +650 -0
- package/dist/tools/data-inspector.js.map +1 -0
- package/dist/tools/deck.d.ts +11 -0
- package/dist/tools/deck.d.ts.map +1 -0
- package/dist/tools/deck.js +170 -0
- package/dist/tools/deck.js.map +1 -0
- package/dist/tools/designer/index.d.ts +6 -0
- package/dist/tools/designer/index.d.ts.map +1 -0
- package/dist/tools/designer/index.js +177 -0
- package/dist/tools/designer/index.js.map +1 -0
- package/dist/tools/designer.d.ts +20 -0
- package/dist/tools/designer.d.ts.map +1 -0
- package/dist/tools/designer.js +75 -0
- package/dist/tools/designer.js.map +1 -0
- package/dist/tools/dojo/index.d.ts +13 -0
- package/dist/tools/dojo/index.d.ts.map +1 -0
- package/dist/tools/dojo/index.js +547 -0
- package/dist/tools/dojo/index.js.map +1 -0
- package/dist/tools/dojo.d.ts +254 -0
- package/dist/tools/dojo.d.ts.map +1 -0
- package/dist/tools/dojo.js +933 -0
- package/dist/tools/dojo.js.map +1 -0
- package/dist/tools/dojoBench.d.ts +49 -0
- package/dist/tools/dojoBench.d.ts.map +1 -0
- package/dist/tools/dojoBench.js +205 -0
- package/dist/tools/dojoBench.js.map +1 -0
- package/dist/tools/dojoGraduated.d.ts +50 -0
- package/dist/tools/dojoGraduated.d.ts.map +1 -0
- package/dist/tools/dojoGraduated.js +174 -0
- package/dist/tools/dojoGraduated.js.map +1 -0
- package/dist/tools/dojoPolicy.d.ts +65 -0
- package/dist/tools/dojoPolicy.d.ts.map +1 -0
- package/dist/tools/dojoPolicy.js +263 -0
- package/dist/tools/dojoPolicy.js.map +1 -0
- package/dist/tools/friction/index.d.ts +7 -0
- package/dist/tools/friction/index.d.ts.map +1 -0
- package/dist/tools/friction/index.js +239 -0
- package/dist/tools/friction/index.js.map +1 -0
- package/dist/tools/friction.d.ts +82 -0
- package/dist/tools/friction.d.ts.map +1 -0
- package/dist/tools/friction.js +331 -0
- package/dist/tools/friction.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +52 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/learnings/index.d.ts +5 -0
- package/dist/tools/learnings/index.d.ts.map +1 -0
- package/dist/tools/learnings/index.js +123 -0
- package/dist/tools/learnings/index.js.map +1 -0
- package/dist/tools/learnings.d.ts +41 -0
- package/dist/tools/learnings.d.ts.map +1 -0
- package/dist/tools/learnings.js +149 -0
- package/dist/tools/learnings.js.map +1 -0
- package/dist/tools/oracle/index.d.ts +5 -0
- package/dist/tools/oracle/index.d.ts.map +1 -0
- package/dist/tools/oracle/index.js +97 -0
- package/dist/tools/oracle/index.js.map +1 -0
- package/dist/tools/oracle.d.ts +90 -0
- package/dist/tools/oracle.d.ts.map +1 -0
- package/dist/tools/oracle.js +529 -0
- package/dist/tools/oracle.js.map +1 -0
- package/dist/tools/policy.d.ts +119 -0
- package/dist/tools/policy.d.ts.map +1 -0
- package/dist/tools/policy.js +406 -0
- package/dist/tools/policy.js.map +1 -0
- package/dist/tools/provenance/index.d.ts +4 -0
- package/dist/tools/provenance/index.d.ts.map +1 -0
- package/dist/tools/provenance/index.js +58 -0
- package/dist/tools/provenance/index.js.map +1 -0
- package/dist/tools/provenance.d.ts +75 -0
- package/dist/tools/provenance.d.ts.map +1 -0
- package/dist/tools/provenance.js +197 -0
- package/dist/tools/provenance.js.map +1 -0
- package/dist/tools/rateLimiter.d.ts +45 -0
- package/dist/tools/rateLimiter.d.ts.map +1 -0
- package/dist/tools/rateLimiter.js +91 -0
- package/dist/tools/rateLimiter.js.map +1 -0
- package/dist/tools/registry/index.d.ts +10 -0
- package/dist/tools/registry/index.d.ts.map +1 -0
- package/dist/tools/registry/index.js +467 -0
- package/dist/tools/registry/index.js.map +1 -0
- package/dist/tools/registry.d.ts +3 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +189 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/roadmap/index.d.ts +9 -0
- package/dist/tools/roadmap/index.d.ts.map +1 -0
- package/dist/tools/roadmap/index.js +250 -0
- package/dist/tools/roadmap/index.js.map +1 -0
- package/dist/tools/roadmap.d.ts +88 -0
- package/dist/tools/roadmap.d.ts.map +1 -0
- package/dist/tools/roadmap.js +365 -0
- package/dist/tools/roadmap.js.map +1 -0
- package/dist/tools/sentinel/index.d.ts +19 -0
- package/dist/tools/sentinel/index.d.ts.map +1 -0
- package/dist/tools/sentinel/index.js +832 -0
- package/dist/tools/sentinel/index.js.map +1 -0
- package/dist/tools/sentinel-scan-data.d.ts +90 -0
- package/dist/tools/sentinel-scan-data.d.ts.map +1 -0
- package/dist/tools/sentinel-scan-data.js +122 -0
- package/dist/tools/sentinel-scan-data.js.map +1 -0
- package/dist/tools/sentinel.d.ts +156 -0
- package/dist/tools/sentinel.d.ts.map +1 -0
- package/dist/tools/sentinel.js +603 -0
- package/dist/tools/sentinel.js.map +1 -0
- package/dist/tools/shared/index.d.ts +4 -0
- package/dist/tools/shared/index.d.ts.map +1 -0
- package/dist/tools/shared/index.js +7 -0
- package/dist/tools/shared/index.js.map +1 -0
- package/dist/tools/shared/project.d.ts +17 -0
- package/dist/tools/shared/project.d.ts.map +1 -0
- package/dist/tools/shared/project.js +36 -0
- package/dist/tools/shared/project.js.map +1 -0
- package/dist/tools/shared/response.d.ts +10 -0
- package/dist/tools/shared/response.d.ts.map +1 -0
- package/dist/tools/shared/response.js +36 -0
- package/dist/tools/shared/response.js.map +1 -0
- package/dist/tools/shared/validation.d.ts +10 -0
- package/dist/tools/shared/validation.d.ts.map +1 -0
- package/dist/tools/shared/validation.js +26 -0
- package/dist/tools/shared/validation.js.map +1 -0
- package/dist/tools/studio/cloud-spine.d.ts +27 -0
- package/dist/tools/studio/cloud-spine.d.ts.map +1 -0
- package/dist/tools/studio/cloud-spine.js +773 -0
- package/dist/tools/studio/cloud-spine.js.map +1 -0
- package/dist/tools/studio/index.d.ts +154 -0
- package/dist/tools/studio/index.d.ts.map +1 -0
- package/dist/tools/studio/index.js +525 -0
- package/dist/tools/studio/index.js.map +1 -0
- package/dist/tools/testSpec.d.ts +122 -0
- package/dist/tools/testSpec.d.ts.map +1 -0
- package/dist/tools/testSpec.js +525 -0
- package/dist/tools/testSpec.js.map +1 -0
- package/dist/tools/toolsIndex.d.ts +5 -0
- package/dist/tools/toolsIndex.d.ts.map +1 -0
- package/dist/tools/toolsIndex.js +37 -0
- package/dist/tools/toolsIndex.js.map +1 -0
- package/dist/tools/types.d.ts +30 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +7 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/voice/index.d.ts +8 -0
- package/dist/tools/voice/index.d.ts.map +1 -0
- package/dist/tools/voice/index.js +176 -0
- package/dist/tools/voice/index.js.map +1 -0
- package/dist/tools/voice.d.ts +291 -0
- package/dist/tools/voice.d.ts.map +1 -0
- package/dist/tools/voice.js +734 -0
- package/dist/tools/voice.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Project Registry
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Maps project IDs/aliases to their filesystem paths.
|
|
5
|
+
// Supports multiple resolution strategies:
|
|
6
|
+
// 1. Registry file (~/.decibel/projects.json or DECIBEL_REGISTRY_PATH)
|
|
7
|
+
// 2. Environment variable (DECIBEL_PROJECT_ROOT for single project)
|
|
8
|
+
// 3. Dynamic discovery (walking up from cwd)
|
|
9
|
+
// ============================================================================
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { dirname } from 'path';
|
|
14
|
+
import { log } from './config.js';
|
|
15
|
+
// ES module equivalent of __dirname
|
|
16
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
+
const __dirname = dirname(__filename);
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Registry Loading
|
|
20
|
+
// ============================================================================
|
|
21
|
+
/**
|
|
22
|
+
* Get the path to the registry file.
|
|
23
|
+
* Default: projects.json in the same directory as this MCP tool.
|
|
24
|
+
*/
|
|
25
|
+
function getRegistryPath() {
|
|
26
|
+
if (process.env.DECIBEL_REGISTRY_PATH) {
|
|
27
|
+
return process.env.DECIBEL_REGISTRY_PATH;
|
|
28
|
+
}
|
|
29
|
+
// Default: projects.json in the MCP repo root (sibling to src/)
|
|
30
|
+
// __dirname at runtime is dist/, so go up one level
|
|
31
|
+
const mcpRoot = path.resolve(__dirname, '..');
|
|
32
|
+
return path.join(mcpRoot, 'projects.json');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Load the project registry from disk
|
|
36
|
+
*/
|
|
37
|
+
function loadRegistry() {
|
|
38
|
+
const registryPath = getRegistryPath();
|
|
39
|
+
if (!fs.existsSync(registryPath)) {
|
|
40
|
+
log(`ProjectRegistry: No registry file at ${registryPath}`);
|
|
41
|
+
return { version: 1, projects: [] };
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const content = fs.readFileSync(registryPath, 'utf-8');
|
|
45
|
+
const data = JSON.parse(content);
|
|
46
|
+
log(`ProjectRegistry: Loaded ${data.projects.length} projects from ${registryPath}`);
|
|
47
|
+
return data;
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
log(`ProjectRegistry: Failed to load registry: ${err}`);
|
|
51
|
+
return { version: 1, projects: [] };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Save the project registry to disk
|
|
56
|
+
*/
|
|
57
|
+
function saveRegistry(registry) {
|
|
58
|
+
const registryPath = getRegistryPath();
|
|
59
|
+
const dir = path.dirname(registryPath);
|
|
60
|
+
if (!fs.existsSync(dir)) {
|
|
61
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2));
|
|
64
|
+
log(`ProjectRegistry: Saved ${registry.projects.length} projects to ${registryPath}`);
|
|
65
|
+
}
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// Discovery Helpers
|
|
68
|
+
// ============================================================================
|
|
69
|
+
/**
|
|
70
|
+
* Walk up directory tree looking for a .decibel folder
|
|
71
|
+
*/
|
|
72
|
+
function findDecibelDir(start) {
|
|
73
|
+
let current = path.resolve(start);
|
|
74
|
+
while (true) {
|
|
75
|
+
const candidate = path.join(current, '.decibel');
|
|
76
|
+
if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) {
|
|
77
|
+
return current; // Return the project root, not the .decibel folder
|
|
78
|
+
}
|
|
79
|
+
const parent = path.dirname(current);
|
|
80
|
+
if (parent === current)
|
|
81
|
+
break;
|
|
82
|
+
current = parent;
|
|
83
|
+
}
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validate that a path contains a .decibel folder
|
|
88
|
+
*/
|
|
89
|
+
function hasDecibelFolder(projectPath) {
|
|
90
|
+
const decibelPath = path.join(projectPath, '.decibel');
|
|
91
|
+
return fs.existsSync(decibelPath) && fs.statSync(decibelPath).isDirectory();
|
|
92
|
+
}
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// Public API
|
|
95
|
+
// ============================================================================
|
|
96
|
+
/**
|
|
97
|
+
* Resolve a project ID or alias to its filesystem path.
|
|
98
|
+
*
|
|
99
|
+
* Resolution order:
|
|
100
|
+
* 1. Check registry for exact ID match
|
|
101
|
+
* 2. Check registry for alias match
|
|
102
|
+
* 3. Check DECIBEL_PROJECT_ROOT env var (if ID matches basename)
|
|
103
|
+
* 4. Check if ID is an absolute path with .decibel
|
|
104
|
+
* 5. Walk up from cwd looking for .decibel (if ID matches discovered project)
|
|
105
|
+
*
|
|
106
|
+
* @param projectId - Project ID, alias, or path
|
|
107
|
+
* @returns Absolute path to the project root
|
|
108
|
+
* @throws Error if project cannot be resolved
|
|
109
|
+
*/
|
|
110
|
+
export function resolveProject(projectId) {
|
|
111
|
+
const registry = loadRegistry();
|
|
112
|
+
// Strategy 1: Exact ID match in registry
|
|
113
|
+
const exactMatch = registry.projects.find((p) => p.id === projectId);
|
|
114
|
+
if (exactMatch) {
|
|
115
|
+
if (!hasDecibelFolder(exactMatch.path)) {
|
|
116
|
+
throw new Error(`Project "${projectId}" registered at ${exactMatch.path} but .decibel folder not found. ` +
|
|
117
|
+
`Update the registry or run 'decibel init' in that directory.`);
|
|
118
|
+
}
|
|
119
|
+
log(`ProjectRegistry: Resolved "${projectId}" via exact ID match`);
|
|
120
|
+
return exactMatch;
|
|
121
|
+
}
|
|
122
|
+
// Strategy 2: Alias match in registry
|
|
123
|
+
const aliasMatch = registry.projects.find((p) => p.aliases?.includes(projectId));
|
|
124
|
+
if (aliasMatch) {
|
|
125
|
+
if (!hasDecibelFolder(aliasMatch.path)) {
|
|
126
|
+
throw new Error(`Project "${projectId}" (alias for "${aliasMatch.id}") registered at ${aliasMatch.path} ` +
|
|
127
|
+
`but .decibel folder not found.`);
|
|
128
|
+
}
|
|
129
|
+
log(`ProjectRegistry: Resolved "${projectId}" via alias -> "${aliasMatch.id}"`);
|
|
130
|
+
return aliasMatch;
|
|
131
|
+
}
|
|
132
|
+
// Strategy 3: DECIBEL_PROJECT_ROOT env var
|
|
133
|
+
const envRoot = process.env.DECIBEL_PROJECT_ROOT;
|
|
134
|
+
if (envRoot && path.basename(envRoot) === projectId) {
|
|
135
|
+
if (hasDecibelFolder(envRoot)) {
|
|
136
|
+
log(`ProjectRegistry: Resolved "${projectId}" via DECIBEL_PROJECT_ROOT`);
|
|
137
|
+
return { id: projectId, path: envRoot };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Strategy 4: Absolute path with .decibel
|
|
141
|
+
if (path.isAbsolute(projectId) && hasDecibelFolder(projectId)) {
|
|
142
|
+
log(`ProjectRegistry: Resolved "${projectId}" as absolute path`);
|
|
143
|
+
return { id: path.basename(projectId), path: projectId };
|
|
144
|
+
}
|
|
145
|
+
// Strategy 5: Discover from cwd
|
|
146
|
+
const discoveredRoot = findDecibelDir(process.cwd());
|
|
147
|
+
if (discoveredRoot && path.basename(discoveredRoot) === projectId) {
|
|
148
|
+
log(`ProjectRegistry: Resolved "${projectId}" via cwd discovery`);
|
|
149
|
+
return { id: projectId, path: discoveredRoot };
|
|
150
|
+
}
|
|
151
|
+
// Strategy 6: If DECIBEL_PROJECT_ROOT is set and has .decibel, use it as fallback
|
|
152
|
+
// This allows tests and scripts to set a project root and use any projectId as a label
|
|
153
|
+
if (envRoot && hasDecibelFolder(envRoot)) {
|
|
154
|
+
log(`ProjectRegistry: Resolved "${projectId}" via DECIBEL_PROJECT_ROOT fallback (treating as label)`);
|
|
155
|
+
return { id: projectId, path: envRoot };
|
|
156
|
+
}
|
|
157
|
+
// Build helpful error message with project_init hint
|
|
158
|
+
const registeredIds = registry.projects.map((p) => p.id);
|
|
159
|
+
const allAliases = registry.projects.flatMap((p) => p.aliases || []);
|
|
160
|
+
const suggestions = [...registeredIds, ...allAliases].filter(Boolean);
|
|
161
|
+
let errorMsg = `PROJECT_NOT_FOUND: "${projectId}".`;
|
|
162
|
+
if (suggestions.length > 0) {
|
|
163
|
+
errorMsg += ` Registered projects: ${suggestions.join(', ')}.`;
|
|
164
|
+
}
|
|
165
|
+
if (discoveredRoot) {
|
|
166
|
+
errorMsg += ` Current directory is in project "${path.basename(discoveredRoot)}".`;
|
|
167
|
+
}
|
|
168
|
+
errorMsg += ` HINT: Run project_init with the path to create and register a new project, or registry_add if .decibel already exists.`;
|
|
169
|
+
throw new Error(errorMsg);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* List all registered projects
|
|
173
|
+
*/
|
|
174
|
+
export function listProjects() {
|
|
175
|
+
const registry = loadRegistry();
|
|
176
|
+
return registry.projects;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Register a new project or update an existing one
|
|
180
|
+
*/
|
|
181
|
+
export function registerProject(entry) {
|
|
182
|
+
const registry = loadRegistry();
|
|
183
|
+
// Validate path exists and has .decibel
|
|
184
|
+
if (!fs.existsSync(entry.path)) {
|
|
185
|
+
throw new Error(`Path does not exist: ${entry.path}`);
|
|
186
|
+
}
|
|
187
|
+
if (!hasDecibelFolder(entry.path)) {
|
|
188
|
+
throw new Error(`No .decibel folder found at ${entry.path}. ` +
|
|
189
|
+
`Initialize with 'decibel init' first.`);
|
|
190
|
+
}
|
|
191
|
+
// Normalize path
|
|
192
|
+
entry.path = path.resolve(entry.path);
|
|
193
|
+
// Check for duplicate ID
|
|
194
|
+
const existingIdx = registry.projects.findIndex((p) => p.id === entry.id);
|
|
195
|
+
if (existingIdx >= 0) {
|
|
196
|
+
// Update existing
|
|
197
|
+
registry.projects[existingIdx] = entry;
|
|
198
|
+
log(`ProjectRegistry: Updated project "${entry.id}"`);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
// Add new
|
|
202
|
+
registry.projects.push(entry);
|
|
203
|
+
log(`ProjectRegistry: Added project "${entry.id}"`);
|
|
204
|
+
}
|
|
205
|
+
saveRegistry(registry);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Remove a project from the registry
|
|
209
|
+
*/
|
|
210
|
+
export function unregisterProject(projectId) {
|
|
211
|
+
const registry = loadRegistry();
|
|
212
|
+
const beforeCount = registry.projects.length;
|
|
213
|
+
registry.projects = registry.projects.filter((p) => p.id !== projectId);
|
|
214
|
+
if (registry.projects.length < beforeCount) {
|
|
215
|
+
saveRegistry(registry);
|
|
216
|
+
log(`ProjectRegistry: Removed project "${projectId}"`);
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Add an alias to an existing project
|
|
223
|
+
*/
|
|
224
|
+
export function addProjectAlias(projectId, alias) {
|
|
225
|
+
const registry = loadRegistry();
|
|
226
|
+
const project = registry.projects.find((p) => p.id === projectId);
|
|
227
|
+
if (!project) {
|
|
228
|
+
throw new Error(`Project not found: ${projectId}`);
|
|
229
|
+
}
|
|
230
|
+
project.aliases = project.aliases || [];
|
|
231
|
+
if (!project.aliases.includes(alias)) {
|
|
232
|
+
project.aliases.push(alias);
|
|
233
|
+
saveRegistry(registry);
|
|
234
|
+
log(`ProjectRegistry: Added alias "${alias}" to project "${projectId}"`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get the registry file path (for display/debugging)
|
|
239
|
+
*/
|
|
240
|
+
export function getRegistryFilePath() {
|
|
241
|
+
return getRegistryPath();
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Get the default project.
|
|
245
|
+
* Resolution order:
|
|
246
|
+
* 1. Project explicitly marked as default
|
|
247
|
+
* 2. DECIBEL_DEFAULT_PROJECT env var
|
|
248
|
+
* 3. If only one project registered, use it
|
|
249
|
+
* 4. Discover from cwd
|
|
250
|
+
*
|
|
251
|
+
* @returns The default project entry or undefined if none can be determined
|
|
252
|
+
*/
|
|
253
|
+
export function getDefaultProject() {
|
|
254
|
+
const registry = loadRegistry();
|
|
255
|
+
// Strategy 1: Explicitly marked default
|
|
256
|
+
const explicitDefault = registry.projects.find((p) => p.default === true);
|
|
257
|
+
if (explicitDefault && hasDecibelFolder(explicitDefault.path)) {
|
|
258
|
+
log(`ProjectRegistry: Using explicit default project "${explicitDefault.id}"`);
|
|
259
|
+
return explicitDefault;
|
|
260
|
+
}
|
|
261
|
+
// Strategy 2: DECIBEL_DEFAULT_PROJECT env var
|
|
262
|
+
const envDefault = process.env.DECIBEL_DEFAULT_PROJECT;
|
|
263
|
+
if (envDefault) {
|
|
264
|
+
const envMatch = registry.projects.find((p) => p.id === envDefault || p.aliases?.includes(envDefault));
|
|
265
|
+
if (envMatch && hasDecibelFolder(envMatch.path)) {
|
|
266
|
+
log(`ProjectRegistry: Using DECIBEL_DEFAULT_PROJECT "${envMatch.id}"`);
|
|
267
|
+
return envMatch;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Strategy 3: If only one project, use it
|
|
271
|
+
const validProjects = registry.projects.filter((p) => hasDecibelFolder(p.path));
|
|
272
|
+
if (validProjects.length === 1) {
|
|
273
|
+
log(`ProjectRegistry: Using only registered project "${validProjects[0].id}" as default`);
|
|
274
|
+
return validProjects[0];
|
|
275
|
+
}
|
|
276
|
+
// Strategy 4: Discover from cwd
|
|
277
|
+
const discoveredRoot = findDecibelDir(process.cwd());
|
|
278
|
+
if (discoveredRoot) {
|
|
279
|
+
const discoveredId = path.basename(discoveredRoot);
|
|
280
|
+
// Check if it matches a registered project
|
|
281
|
+
const registeredMatch = registry.projects.find((p) => p.id === discoveredId);
|
|
282
|
+
if (registeredMatch) {
|
|
283
|
+
log(`ProjectRegistry: Using cwd-discovered project "${registeredMatch.id}" as default`);
|
|
284
|
+
return registeredMatch;
|
|
285
|
+
}
|
|
286
|
+
// Return an ad-hoc entry for the discovered project
|
|
287
|
+
log(`ProjectRegistry: Using cwd-discovered unregistered project "${discoveredId}" as default`);
|
|
288
|
+
return { id: discoveredId, path: discoveredRoot };
|
|
289
|
+
}
|
|
290
|
+
log(`ProjectRegistry: No default project could be determined`);
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Set a project as the default
|
|
295
|
+
*/
|
|
296
|
+
export function setDefaultProject(projectId) {
|
|
297
|
+
const registry = loadRegistry();
|
|
298
|
+
const project = registry.projects.find((p) => p.id === projectId);
|
|
299
|
+
if (!project) {
|
|
300
|
+
throw new Error(`Project not found: ${projectId}`);
|
|
301
|
+
}
|
|
302
|
+
// Clear existing defaults
|
|
303
|
+
for (const p of registry.projects) {
|
|
304
|
+
p.default = false;
|
|
305
|
+
}
|
|
306
|
+
// Set new default
|
|
307
|
+
project.default = true;
|
|
308
|
+
saveRegistry(registry);
|
|
309
|
+
log(`ProjectRegistry: Set "${projectId}" as default project`);
|
|
310
|
+
}
|
|
311
|
+
// ============================================================================
|
|
312
|
+
// Input Normalization Helpers
|
|
313
|
+
// ============================================================================
|
|
314
|
+
/**
|
|
315
|
+
* Normalize projectId from various input formats.
|
|
316
|
+
* Handles both camelCase (projectId) and snake_case (project_id).
|
|
317
|
+
* This allows tools to accept inputs from Claude regardless of which format it uses.
|
|
318
|
+
*/
|
|
319
|
+
export function normalizeProjectId(input) {
|
|
320
|
+
return input.projectId || input.project_id;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Resolve project and return useful paths.
|
|
324
|
+
* This is the primary helper for tools to get project paths.
|
|
325
|
+
*
|
|
326
|
+
* @param projectId - Project ID, alias, or path (optional, uses default if not provided)
|
|
327
|
+
* @returns Resolved project paths
|
|
328
|
+
* @throws Error if project cannot be resolved
|
|
329
|
+
*/
|
|
330
|
+
export function resolveProjectPaths(projectId) {
|
|
331
|
+
let project;
|
|
332
|
+
if (projectId) {
|
|
333
|
+
project = resolveProject(projectId);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
const defaultProject = getDefaultProject();
|
|
337
|
+
if (!defaultProject) {
|
|
338
|
+
throw new Error('No project specified and no default project found. ' +
|
|
339
|
+
'Either specify projectId or register a project with the registry.');
|
|
340
|
+
}
|
|
341
|
+
project = defaultProject;
|
|
342
|
+
}
|
|
343
|
+
const decibelPath = path.join(project.path, '.decibel');
|
|
344
|
+
return {
|
|
345
|
+
id: project.id,
|
|
346
|
+
projectPath: project.path,
|
|
347
|
+
decibelPath,
|
|
348
|
+
subPath: (...segments) => path.join(decibelPath, ...segments),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Validate that a write path is within the project's .decibel folder.
|
|
353
|
+
* Call this before any file write to prevent escaping project boundaries.
|
|
354
|
+
*/
|
|
355
|
+
export function validateWritePath(targetPath, resolved) {
|
|
356
|
+
const normalized = path.normalize(targetPath);
|
|
357
|
+
if (!normalized.startsWith(resolved.decibelPath)) {
|
|
358
|
+
throw new Error(`SECURITY: Write path ${targetPath} is outside project .decibel folder. ` +
|
|
359
|
+
`Expected path under: ${resolved.decibelPath}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
//# sourceMappingURL=projectRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectRegistry.js","sourceRoot":"","sources":["../src/projectRegistry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type IssueStatus = 'open' | 'in_progress' | 'done' | 'blocked';
|
|
2
|
+
export type IssuePriority = 'low' | 'medium' | 'high';
|
|
3
|
+
export interface SentinelIssue {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
project: string;
|
|
7
|
+
status: IssueStatus;
|
|
8
|
+
priority?: IssuePriority;
|
|
9
|
+
epicId?: string;
|
|
10
|
+
tags?: string[];
|
|
11
|
+
created_at?: string;
|
|
12
|
+
updated_at?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface CreateIssueInput {
|
|
17
|
+
projectId: string;
|
|
18
|
+
title: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
epicId?: string;
|
|
21
|
+
priority?: IssuePriority;
|
|
22
|
+
tags?: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface CreateIssueOutput extends SentinelIssue {
|
|
25
|
+
filePath: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* List all issues for a project
|
|
29
|
+
* Reads from both .decibel/ and decibel/ paths, deduping by filename
|
|
30
|
+
*/
|
|
31
|
+
export declare function listIssuesForProject(projectId: string): Promise<SentinelIssue[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Create a new issue for a project
|
|
34
|
+
*/
|
|
35
|
+
export declare function createIssue(input: CreateIssueInput): Promise<CreateIssueOutput>;
|
|
36
|
+
/**
|
|
37
|
+
* Filter issues by status
|
|
38
|
+
*/
|
|
39
|
+
export declare function filterByStatus(issues: SentinelIssue[], status: IssueStatus): SentinelIssue[];
|
|
40
|
+
/**
|
|
41
|
+
* Filter issues by epic ID
|
|
42
|
+
*/
|
|
43
|
+
export declare function filterByEpicId(issues: SentinelIssue[], epicId: string): SentinelIssue[];
|
|
44
|
+
//# sourceMappingURL=sentinelIssues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentinelIssues.d.ts","sourceRoot":"","sources":["../src/sentinelIssues.ts"],"names":[],"mappings":"AAUA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,aAAa,GAAG,MAAM,GAAG,SAAS,CAAC;AACtE,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,iBAAkB,SAAQ,aAAa;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAoFD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,EAAE,CAAC,CAgE1B;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,iBAAiB,CAAC,CA4E5B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EAAE,EACvB,MAAM,EAAE,WAAW,GAClB,aAAa,EAAE,CAEjB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EAAE,EACvB,MAAM,EAAE,MAAM,GACb,aAAa,EAAE,CAEjB"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { parse as parseYaml, parseAllDocuments, stringify as stringifyYaml } from 'yaml';
|
|
4
|
+
import { log } from './config.js';
|
|
5
|
+
import { getWritePath, readFilesFromBothPaths } from './decibelPaths.js';
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// Constants
|
|
8
|
+
// ============================================================================
|
|
9
|
+
const ISSUES_SUBPATH = 'sentinel/issues';
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Helpers
|
|
12
|
+
// ============================================================================
|
|
13
|
+
/**
|
|
14
|
+
* Slugify a title for use in filename
|
|
15
|
+
*/
|
|
16
|
+
function slugify(text) {
|
|
17
|
+
return text
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
20
|
+
.replace(/^-|-$/g, '')
|
|
21
|
+
.substring(0, 50);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Extract numeric suffix from issue ID (e.g., "ISS-0007" -> 7)
|
|
25
|
+
*/
|
|
26
|
+
function extractIssueNumber(id) {
|
|
27
|
+
const match = id.match(/^ISS-(\d+)$/i);
|
|
28
|
+
return match ? parseInt(match[1], 10) : 0;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Format issue ID with zero-padding
|
|
32
|
+
*/
|
|
33
|
+
function formatIssueId(num) {
|
|
34
|
+
return `ISS-${num.toString().padStart(4, '0')}`;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Ensure directory exists
|
|
38
|
+
*/
|
|
39
|
+
async function ensureDir(dirPath) {
|
|
40
|
+
try {
|
|
41
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// Directory already exists or other error
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Safely parse YAML content that might contain multiple documents (frontmatter format).
|
|
49
|
+
* Returns the first document's contents, or throws if no valid document found.
|
|
50
|
+
*/
|
|
51
|
+
function safeParseYaml(content) {
|
|
52
|
+
// First, try simple parse (most common case)
|
|
53
|
+
try {
|
|
54
|
+
return parseYaml(content);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
// Check if error is about multiple documents
|
|
58
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
59
|
+
if (!message.includes('multiple documents')) {
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Handle multi-document YAML (frontmatter format with --- delimiters)
|
|
64
|
+
const docs = parseAllDocuments(content);
|
|
65
|
+
if (docs.length === 0) {
|
|
66
|
+
throw new Error('No YAML documents found');
|
|
67
|
+
}
|
|
68
|
+
// Return the first document (usually the frontmatter)
|
|
69
|
+
const firstDoc = docs[0].toJSON();
|
|
70
|
+
if (typeof firstDoc !== 'object' || firstDoc === null) {
|
|
71
|
+
throw new Error('First YAML document is not an object');
|
|
72
|
+
}
|
|
73
|
+
return firstDoc;
|
|
74
|
+
}
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// Public API
|
|
77
|
+
// ============================================================================
|
|
78
|
+
/**
|
|
79
|
+
* List all issues for a project
|
|
80
|
+
* Reads from both .decibel/ and decibel/ paths, deduping by filename
|
|
81
|
+
*/
|
|
82
|
+
export async function listIssuesForProject(projectId) {
|
|
83
|
+
const issues = [];
|
|
84
|
+
const seenIds = new Set();
|
|
85
|
+
// Read from both .decibel/ and decibel/ paths
|
|
86
|
+
const files = await readFilesFromBothPaths(projectId, ISSUES_SUBPATH);
|
|
87
|
+
if (files.length === 0) {
|
|
88
|
+
log(`sentinelIssues: No issues found for project: ${projectId}`);
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
for (const { filePath, source } of files) {
|
|
92
|
+
try {
|
|
93
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
94
|
+
const parsed = safeParseYaml(content);
|
|
95
|
+
// Validate required fields
|
|
96
|
+
const id = parsed.id;
|
|
97
|
+
const title = parsed.title;
|
|
98
|
+
if (!id || !title) {
|
|
99
|
+
log(`sentinelIssues: Skipping ${filePath} - missing id or title`);
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
// Skip duplicates (primary takes precedence)
|
|
103
|
+
if (seenIds.has(id)) {
|
|
104
|
+
log(`sentinelIssues: Skipping duplicate ${id} from ${source} path`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
seenIds.add(id);
|
|
108
|
+
const issue = {
|
|
109
|
+
id,
|
|
110
|
+
title,
|
|
111
|
+
project: parsed.project || projectId,
|
|
112
|
+
status: parsed.status || 'open',
|
|
113
|
+
priority: parsed.priority,
|
|
114
|
+
epicId: parsed.epic_id || parsed.epicId,
|
|
115
|
+
tags: parsed.tags,
|
|
116
|
+
created_at: parsed.created_at,
|
|
117
|
+
updated_at: parsed.updated_at,
|
|
118
|
+
description: parsed.description,
|
|
119
|
+
};
|
|
120
|
+
// Copy any extra fields
|
|
121
|
+
for (const key of Object.keys(parsed)) {
|
|
122
|
+
if (!(key in issue)) {
|
|
123
|
+
issue[key] = parsed[key];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
issues.push(issue);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
130
|
+
log(`sentinelIssues: Failed to parse ${filePath}: ${message}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Sort by ID (newest first)
|
|
134
|
+
issues.sort((a, b) => extractIssueNumber(b.id) - extractIssueNumber(a.id));
|
|
135
|
+
return issues;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Create a new issue for a project
|
|
139
|
+
*/
|
|
140
|
+
export async function createIssue(input) {
|
|
141
|
+
const { projectId, title, description, epicId, priority, tags } = input;
|
|
142
|
+
// Always write to .decibel/ (primary path)
|
|
143
|
+
const issuesDir = await getWritePath(projectId, ISSUES_SUBPATH);
|
|
144
|
+
await ensureDir(issuesDir);
|
|
145
|
+
// Find next issue number
|
|
146
|
+
const existingIssues = await listIssuesForProject(projectId);
|
|
147
|
+
const maxNum = existingIssues.reduce((max, issue) => Math.max(max, extractIssueNumber(issue.id)), 0);
|
|
148
|
+
const newNum = maxNum + 1;
|
|
149
|
+
const newId = formatIssueId(newNum);
|
|
150
|
+
// Build filename
|
|
151
|
+
const slug = slugify(title);
|
|
152
|
+
const filename = `${newId}-${slug}.yml`;
|
|
153
|
+
const filePath = path.join(issuesDir, filename);
|
|
154
|
+
// Build issue object
|
|
155
|
+
const now = new Date().toISOString();
|
|
156
|
+
const issue = {
|
|
157
|
+
id: newId,
|
|
158
|
+
title,
|
|
159
|
+
project: projectId,
|
|
160
|
+
status: 'open',
|
|
161
|
+
priority: priority || 'medium',
|
|
162
|
+
tags: tags || [],
|
|
163
|
+
created_at: now,
|
|
164
|
+
updated_at: now,
|
|
165
|
+
};
|
|
166
|
+
if (epicId) {
|
|
167
|
+
issue.epicId = epicId;
|
|
168
|
+
}
|
|
169
|
+
if (description) {
|
|
170
|
+
issue.description = description;
|
|
171
|
+
}
|
|
172
|
+
// Build YAML content
|
|
173
|
+
// Use a specific field order for cleaner output
|
|
174
|
+
const yamlObj = {
|
|
175
|
+
id: issue.id,
|
|
176
|
+
title: issue.title,
|
|
177
|
+
project: issue.project,
|
|
178
|
+
status: issue.status,
|
|
179
|
+
priority: issue.priority,
|
|
180
|
+
};
|
|
181
|
+
if (epicId) {
|
|
182
|
+
yamlObj.epic_id = epicId;
|
|
183
|
+
}
|
|
184
|
+
yamlObj.tags = issue.tags;
|
|
185
|
+
yamlObj.created_at = issue.created_at;
|
|
186
|
+
yamlObj.updated_at = issue.updated_at;
|
|
187
|
+
if (description) {
|
|
188
|
+
yamlObj.description = description;
|
|
189
|
+
}
|
|
190
|
+
const yamlContent = stringifyYaml(yamlObj, {
|
|
191
|
+
lineWidth: 0, // Don't wrap lines
|
|
192
|
+
});
|
|
193
|
+
// Write file
|
|
194
|
+
await fs.writeFile(filePath, yamlContent, 'utf-8');
|
|
195
|
+
log(`sentinelIssues: Created issue at ${filePath}`);
|
|
196
|
+
return {
|
|
197
|
+
...issue,
|
|
198
|
+
filePath,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Filter issues by status
|
|
203
|
+
*/
|
|
204
|
+
export function filterByStatus(issues, status) {
|
|
205
|
+
return issues.filter((issue) => issue.status === status);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Filter issues by epic ID
|
|
209
|
+
*/
|
|
210
|
+
export function filterByEpicId(issues, epicId) {
|
|
211
|
+
return issues.filter((issue) => issue.epicId === epicId);
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=sentinelIssues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentinelIssues.js","sourceRoot":"","sources":["../src/sentinelIssues.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,iBAAiB,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AACzF,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAqCzE,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAEzC,+EAA+E;AAC/E,UAAU;AACV,+EAA+E;AAE/E;;GAEG;AACH,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,IAAI;SACR,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtB,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,EAAU;IACpC,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,OAAO,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,SAAS,CAAC,OAAe;IACtC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;IAC5C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,aAAa,CAAC,OAAe;IACpC,6CAA6C;IAC7C,IAAI,CAAC;QACH,OAAO,SAAS,CAAC,OAAO,CAA4B,CAAC;IACvD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,6CAA6C;QAC7C,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC5C,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,sEAAsE;IACtE,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,sDAAsD;IACtD,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,QAAmC,CAAC;AAC7C,CAAC;AAED,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,SAAiB;IAEjB,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,8CAA8C;IAC9C,MAAM,KAAK,GAAG,MAAM,sBAAsB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAEtE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,GAAG,CAAC,gDAAgD,SAAS,EAAE,CAAC,CAAC;QACjE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACzC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACrD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YAEtC,2BAA2B;YAC3B,MAAM,EAAE,GAAG,MAAM,CAAC,EAAY,CAAC;YAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAe,CAAC;YAErC,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;gBAClB,GAAG,CAAC,4BAA4B,QAAQ,wBAAwB,CAAC,CAAC;gBAClE,SAAS;YACX,CAAC;YAED,6CAA6C;YAC7C,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACpB,GAAG,CAAC,sCAAsC,EAAE,SAAS,MAAM,OAAO,CAAC,CAAC;gBACpE,SAAS;YACX,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAEhB,MAAM,KAAK,GAAkB;gBAC3B,EAAE;gBACF,KAAK;gBACL,OAAO,EAAG,MAAM,CAAC,OAAkB,IAAI,SAAS;gBAChD,MAAM,EAAG,MAAM,CAAC,MAAsB,IAAI,MAAM;gBAChD,QAAQ,EAAE,MAAM,CAAC,QAAqC;gBACtD,MAAM,EAAG,MAAM,CAAC,OAAkB,IAAK,MAAM,CAAC,MAAiB;gBAC/D,IAAI,EAAE,MAAM,CAAC,IAA4B;gBACzC,UAAU,EAAE,MAAM,CAAC,UAAgC;gBACnD,UAAU,EAAE,MAAM,CAAC,UAAgC;gBACnD,WAAW,EAAE,MAAM,CAAC,WAAiC;aACtD,CAAC;YAEF,wBAAwB;YACxB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtC,IAAI,CAAC,CAAC,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC;oBACpB,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,GAAG,CAAC,mCAAmC,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,KAAuB;IAEvB,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IAExE,2CAA2C;IAC3C,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAChE,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;IAE3B,yBAAyB;IACzB,MAAM,cAAc,GAAG,MAAM,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC7D,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAClC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAC3D,CAAC,CACF,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;IAC1B,MAAM,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAEpC,iBAAiB;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,QAAQ,GAAG,GAAG,KAAK,IAAI,IAAI,MAAM,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhD,qBAAqB;IACrB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,KAAK,GAAkB;QAC3B,EAAE,EAAE,KAAK;QACT,KAAK;QACL,OAAO,EAAE,SAAS;QAClB,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,QAAQ,IAAI,QAAQ;QAC9B,IAAI,EAAE,IAAI,IAAI,EAAE;QAChB,UAAU,EAAE,GAAG;QACf,UAAU,EAAE,GAAG;KAChB,CAAC;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QAChB,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;IAClC,CAAC;IAED,qBAAqB;IACrB,gDAAgD;IAChD,MAAM,OAAO,GAA4B;QACvC,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,CAAC;IAEF,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,OAAO,GAAG,MAAM,CAAC;IAC3B,CAAC;IAED,OAAO,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAC1B,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IACtC,OAAO,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;IAEtC,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;IACpC,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,EAAE;QACzC,SAAS,EAAE,CAAC,EAAE,mBAAmB;KAClC,CAAC,CAAC;IAEH,aAAa;IACb,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IACnD,GAAG,CAAC,oCAAoC,QAAQ,EAAE,CAAC,CAAC;IAEpD,OAAO;QACL,GAAG,KAAK;QACR,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAuB,EACvB,MAAmB;IAEnB,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAuB,EACvB,MAAc;IAEd,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;AAC3D,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
|