@codemcp/workflows 6.4.0 → 6.5.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/package.json +2 -2
- package/packages/cli/dist/{chunk-D2Q6Y3QQ.js → chunk-4AZGS2GG.js} +321 -388
- package/packages/cli/dist/{cli-DXJJF56V.js → cli-ZCCFBQTP.js} +3 -3
- package/packages/cli/dist/{dist-W7PPKVFG.js → dist-I6VSREAJ.js} +11 -5
- package/packages/cli/dist/{dist-W7VMGB3G.js → dist-MW7THWM3.js} +875 -1136
- package/packages/cli/dist/index.js +2 -2
- package/packages/cli/package.json +1 -1
- package/packages/cli/resources/workflows/bugfix.yaml +14 -0
- package/packages/cli/resources/workflows/epcc.yaml +12 -0
- package/packages/cli/resources/workflows/greenfield.yaml +16 -0
- package/packages/cli/resources/workflows/minor.yaml +8 -0
- package/packages/cli/resources/workflows/tdd.yaml +10 -0
- package/packages/cli/resources/workflows/waterfall.yaml +16 -0
- package/packages/core/dist/beads-integration.d.ts +3 -5
- package/packages/core/dist/beads-integration.js +29 -35
- package/packages/core/dist/beads-integration.js.map +1 -1
- package/packages/core/dist/beads-state-manager.d.ts +3 -1
- package/packages/core/dist/beads-state-manager.js +17 -15
- package/packages/core/dist/beads-state-manager.js.map +1 -1
- package/packages/core/dist/file-detection-manager.js +15 -22
- package/packages/core/dist/file-detection-manager.js.map +1 -1
- package/packages/core/dist/index.d.ts +1 -0
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/instruction-generator.d.ts +3 -7
- package/packages/core/dist/instruction-generator.js +17 -25
- package/packages/core/dist/instruction-generator.js.map +1 -1
- package/packages/core/dist/interfaces/instruction-generator.interface.d.ts +13 -4
- package/packages/core/dist/interfaces/plan-manager.interface.d.ts +9 -0
- package/packages/core/dist/logger.d.ts +49 -20
- package/packages/core/dist/logger.js +65 -141
- package/packages/core/dist/logger.js.map +1 -1
- package/packages/core/dist/plan-manager.d.ts +6 -4
- package/packages/core/dist/plan-manager.js +19 -15
- package/packages/core/dist/plan-manager.js.map +1 -1
- package/packages/core/dist/project-docs-manager.d.ts +3 -1
- package/packages/core/dist/project-docs-manager.js +11 -9
- package/packages/core/dist/project-docs-manager.js.map +1 -1
- package/packages/core/dist/state-machine-loader.d.ts +16 -0
- package/packages/core/dist/state-machine-loader.js +29 -0
- package/packages/core/dist/state-machine-loader.js.map +1 -1
- package/packages/core/dist/state-machine-types.d.ts +8 -0
- package/packages/core/dist/string-utils.d.ts +8 -0
- package/packages/core/dist/string-utils.js +14 -0
- package/packages/core/dist/string-utils.js.map +1 -0
- package/packages/core/dist/task-backend.d.ts +6 -3
- package/packages/core/dist/task-backend.js +10 -8
- package/packages/core/dist/task-backend.js.map +1 -1
- package/packages/core/dist/transition-engine.d.ts +3 -6
- package/packages/core/dist/transition-engine.js +31 -76
- package/packages/core/dist/transition-engine.js.map +1 -1
- package/packages/core/dist/workflow-manager.d.ts +2 -0
- package/packages/core/dist/workflow-manager.js +14 -2
- package/packages/core/dist/workflow-manager.js.map +1 -1
- package/packages/core/package.json +1 -1
- package/packages/core/resources/workflows/bugfix.yaml +14 -0
- package/packages/core/resources/workflows/epcc.yaml +12 -0
- package/packages/core/resources/workflows/greenfield.yaml +16 -0
- package/packages/core/resources/workflows/minor.yaml +8 -0
- package/packages/core/resources/workflows/tdd.yaml +10 -0
- package/packages/core/resources/workflows/waterfall.yaml +16 -0
- package/packages/docs/.vitepress/dist/workflows/bugfix.yaml +14 -0
- package/packages/docs/.vitepress/dist/workflows/epcc.yaml +12 -0
- package/packages/docs/.vitepress/dist/workflows/greenfield.yaml +16 -0
- package/packages/docs/.vitepress/dist/workflows/minor.yaml +8 -0
- package/packages/docs/.vitepress/dist/workflows/tdd.yaml +10 -0
- package/packages/docs/.vitepress/dist/workflows/waterfall.yaml +16 -0
- package/packages/docs/package.json +1 -1
- package/packages/mcp-server/dist/index.d.ts +1027 -0
- package/packages/mcp-server/dist/index.js +879 -1140
- package/packages/mcp-server/package.json +1 -1
- package/packages/mcp-server/resources/workflows/bugfix.yaml +14 -0
- package/packages/mcp-server/resources/workflows/epcc.yaml +12 -0
- package/packages/mcp-server/resources/workflows/greenfield.yaml +16 -0
- package/packages/mcp-server/resources/workflows/minor.yaml +8 -0
- package/packages/mcp-server/resources/workflows/tdd.yaml +10 -0
- package/packages/mcp-server/resources/workflows/waterfall.yaml +16 -0
- package/packages/opencode-plugin/dist/index.d.ts +9 -0
- package/packages/opencode-plugin/dist/index.js +11 -0
- package/packages/opencode-plugin/dist/index.js.map +1 -0
- package/packages/opencode-plugin/dist/opencode-logger.d.ts +21 -0
- package/packages/opencode-plugin/dist/opencode-logger.js +104 -0
- package/packages/opencode-plugin/dist/opencode-logger.js.map +1 -0
- package/packages/opencode-plugin/dist/plugin.d.ts +23 -0
- package/packages/opencode-plugin/dist/plugin.js +395 -0
- package/packages/opencode-plugin/dist/plugin.js.map +1 -0
- package/packages/opencode-plugin/dist/server-context.d.ts +40 -0
- package/packages/opencode-plugin/dist/server-context.js +96 -0
- package/packages/opencode-plugin/dist/server-context.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/conduct-review.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/conduct-review.js +37 -0
- package/packages/opencode-plugin/dist/tool-handlers/conduct-review.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/proceed-to-phase.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/proceed-to-phase.js +74 -0
- package/packages/opencode-plugin/dist/tool-handlers/proceed-to-phase.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/reset-development.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/reset-development.js +63 -0
- package/packages/opencode-plugin/dist/tool-handlers/reset-development.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/setup-project-docs.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/setup-project-docs.js +74 -0
- package/packages/opencode-plugin/dist/tool-handlers/setup-project-docs.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/start-development.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/start-development.js +69 -0
- package/packages/opencode-plugin/dist/tool-handlers/start-development.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/tool-helper.d.ts +10 -0
- package/packages/opencode-plugin/dist/tool-handlers/tool-helper.js +7 -0
- package/packages/opencode-plugin/dist/tool-handlers/tool-helper.js.map +1 -0
- package/packages/opencode-plugin/dist/types.d.ts +193 -0
- package/packages/opencode-plugin/dist/types.js +8 -0
- package/packages/opencode-plugin/dist/types.js.map +1 -0
- package/packages/opencode-plugin/dist/utils.d.ts +14 -0
- package/packages/opencode-plugin/dist/utils.js +26 -0
- package/packages/opencode-plugin/dist/utils.js.map +1 -0
- package/packages/opencode-plugin/package.json +52 -0
- package/packages/opencode-tui-plugin/package.json +46 -0
- package/packages/visualizer/package.json +1 -1
- package/resources/workflows/bugfix.yaml +14 -0
- package/resources/workflows/epcc.yaml +12 -0
- package/resources/workflows/greenfield.yaml +16 -0
- package/resources/workflows/minor.yaml +8 -0
- package/resources/workflows/tdd.yaml +10 -0
- package/resources/workflows/waterfall.yaml +16 -0
|
@@ -2650,25 +2650,21 @@ var LogLevel;
|
|
|
2650
2650
|
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
2651
2651
|
LogLevel2[LogLevel2["SILENT"] = 4] = "SILENT";
|
|
2652
2652
|
})(LogLevel || (LogLevel = {}));
|
|
2653
|
-
var
|
|
2653
|
+
var logSinkInstance = null;
|
|
2654
2654
|
var currentLoggingLevel = null;
|
|
2655
2655
|
function isTestMode() {
|
|
2656
|
-
if (process.env
|
|
2656
|
+
if (process.env["NODE_ENV"] === "test" || process.env["VITEST"] === "true") {
|
|
2657
2657
|
return true;
|
|
2658
2658
|
}
|
|
2659
|
-
|
|
2660
|
-
if (cwd.includes("/tmp/") || cwd.includes("temp") || cwd.includes("test-")) {
|
|
2661
|
-
return true;
|
|
2662
|
-
}
|
|
2663
|
-
if (process.env.LOG_LEVEL === "ERROR") {
|
|
2659
|
+
if (process.env["LOG_LEVEL"] === "ERROR") {
|
|
2664
2660
|
return true;
|
|
2665
2661
|
}
|
|
2666
2662
|
return false;
|
|
2667
2663
|
}
|
|
2668
|
-
function
|
|
2669
|
-
|
|
2664
|
+
function registerLogSink(sink) {
|
|
2665
|
+
logSinkInstance = sink;
|
|
2670
2666
|
}
|
|
2671
|
-
function
|
|
2667
|
+
function setLoggingLevelFromString(level) {
|
|
2672
2668
|
const levelMap = {
|
|
2673
2669
|
debug: LogLevel.DEBUG,
|
|
2674
2670
|
info: LogLevel.INFO,
|
|
@@ -2708,7 +2704,7 @@ var Logger = class _Logger {
|
|
|
2708
2704
|
return LogLevel.INFO;
|
|
2709
2705
|
}
|
|
2710
2706
|
getLogLevelFromEnv() {
|
|
2711
|
-
const envLevel = process.env
|
|
2707
|
+
const envLevel = process.env["LOG_LEVEL"]?.toUpperCase();
|
|
2712
2708
|
switch (envLevel) {
|
|
2713
2709
|
case "DEBUG":
|
|
2714
2710
|
return LogLevel.DEBUG;
|
|
@@ -2733,31 +2729,15 @@ var Logger = class _Logger {
|
|
|
2733
2729
|
return `[${timestamp2}] ${level.toUpperCase()} [${this.component}] ${message}${contextStr}`;
|
|
2734
2730
|
}
|
|
2735
2731
|
/**
|
|
2736
|
-
* Send log message to
|
|
2732
|
+
* Send log message to registered sink if available
|
|
2737
2733
|
*/
|
|
2738
|
-
async
|
|
2739
|
-
if (
|
|
2734
|
+
async sendToSink(level, message, context) {
|
|
2735
|
+
if (logSinkInstance) {
|
|
2740
2736
|
try {
|
|
2741
|
-
|
|
2742
|
-
if (context) {
|
|
2743
|
-
try {
|
|
2744
|
-
const contextStr = JSON.stringify(context, null, 0);
|
|
2745
|
-
logData = `${message} ${contextStr}`;
|
|
2746
|
-
} catch (_error) {
|
|
2747
|
-
logData = `${message} [context serialization failed]`;
|
|
2748
|
-
}
|
|
2749
|
-
}
|
|
2750
|
-
await mcpServerInstance.server.notification({
|
|
2751
|
-
method: "notifications/message",
|
|
2752
|
-
params: {
|
|
2753
|
-
level,
|
|
2754
|
-
logger: this.component,
|
|
2755
|
-
data: logData
|
|
2756
|
-
}
|
|
2757
|
-
});
|
|
2737
|
+
await logSinkInstance.log(level, this.component, message, context);
|
|
2758
2738
|
} catch (error) {
|
|
2759
2739
|
if (!isTestMode()) {
|
|
2760
|
-
process.stderr.write(`[
|
|
2740
|
+
process.stderr.write(`[LOG-SINK-ERROR] Failed to send log to sink: ${error}
|
|
2761
2741
|
`);
|
|
2762
2742
|
}
|
|
2763
2743
|
}
|
|
@@ -2765,85 +2745,42 @@ var Logger = class _Logger {
|
|
|
2765
2745
|
}
|
|
2766
2746
|
debug(message, context) {
|
|
2767
2747
|
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2748
|
+
if (!logSinkInstance) {
|
|
2749
|
+
const formattedMessage = this.formatMessage("debug", message, context);
|
|
2750
|
+
process.stderr.write(formattedMessage + "\n");
|
|
2751
|
+
}
|
|
2752
|
+
this.sendToSink("debug", message, context).catch(() => {
|
|
2771
2753
|
});
|
|
2772
2754
|
}
|
|
2773
2755
|
}
|
|
2774
2756
|
info(message, context) {
|
|
2775
2757
|
if (this.shouldLog(LogLevel.INFO)) {
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
});
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
|
-
/**
|
|
2783
|
-
* Send enhanced MCP notifications with better formatting for important events
|
|
2784
|
-
*/
|
|
2785
|
-
async sendEnhancedMcpNotification(level, message, context) {
|
|
2786
|
-
if (mcpServerInstance) {
|
|
2787
|
-
try {
|
|
2788
|
-
let enhancedMessage = message;
|
|
2789
|
-
let notificationLevel = level;
|
|
2790
|
-
if (context && (context.from || context.to) && message.includes("transition")) {
|
|
2791
|
-
const from = context.from ? this.capitalizePhase(context.from) : "";
|
|
2792
|
-
const to = context.to ? this.capitalizePhase(context.to) : "";
|
|
2793
|
-
if (from && to) {
|
|
2794
|
-
enhancedMessage = `Phase Transition: ${from} \u2192 ${to}`;
|
|
2795
|
-
notificationLevel = "info";
|
|
2796
|
-
}
|
|
2797
|
-
}
|
|
2798
|
-
if (message.includes("initialized successfully")) {
|
|
2799
|
-
enhancedMessage = "\u{1F680} Vibe Feature MCP Server Ready";
|
|
2800
|
-
notificationLevel = "info";
|
|
2801
|
-
}
|
|
2802
|
-
let logData = enhancedMessage;
|
|
2803
|
-
if (context) {
|
|
2804
|
-
try {
|
|
2805
|
-
const contextStr = JSON.stringify(context, null, 0);
|
|
2806
|
-
logData = `${enhancedMessage} ${contextStr}`;
|
|
2807
|
-
} catch (_error) {
|
|
2808
|
-
logData = `${enhancedMessage} [context serialization failed]`;
|
|
2809
|
-
}
|
|
2810
|
-
}
|
|
2811
|
-
await mcpServerInstance.server.notification({
|
|
2812
|
-
method: "notifications/message",
|
|
2813
|
-
params: {
|
|
2814
|
-
level: notificationLevel,
|
|
2815
|
-
logger: this.component,
|
|
2816
|
-
data: logData
|
|
2817
|
-
}
|
|
2818
|
-
});
|
|
2819
|
-
} catch (error) {
|
|
2820
|
-
if (!isTestMode()) {
|
|
2821
|
-
process.stderr.write(`[MCP-LOG-ERROR] Failed to send log notification: ${error}
|
|
2822
|
-
`);
|
|
2823
|
-
}
|
|
2758
|
+
if (!logSinkInstance) {
|
|
2759
|
+
const formattedMessage = this.formatMessage("info", message, context);
|
|
2760
|
+
process.stderr.write(formattedMessage + "\n");
|
|
2824
2761
|
}
|
|
2762
|
+
this.sendToSink("info", message, context).catch(() => {
|
|
2763
|
+
});
|
|
2825
2764
|
}
|
|
2826
2765
|
}
|
|
2827
|
-
/**
|
|
2828
|
-
* Capitalize phase name for display
|
|
2829
|
-
*/
|
|
2830
|
-
capitalizePhase(phase) {
|
|
2831
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
2832
|
-
}
|
|
2833
2766
|
warn(message, context) {
|
|
2834
2767
|
if (this.shouldLog(LogLevel.WARN)) {
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2768
|
+
if (!logSinkInstance) {
|
|
2769
|
+
const formattedMessage = this.formatMessage("warn", message, context);
|
|
2770
|
+
process.stderr.write(formattedMessage + "\n");
|
|
2771
|
+
}
|
|
2772
|
+
this.sendToSink("warning", message, context).catch(() => {
|
|
2838
2773
|
});
|
|
2839
2774
|
}
|
|
2840
2775
|
}
|
|
2841
2776
|
error(message, error, context) {
|
|
2842
2777
|
if (this.shouldLog(LogLevel.ERROR)) {
|
|
2843
2778
|
const errorContext = error ? { ...context, error: error.message, stack: error.stack } : context;
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2779
|
+
if (!logSinkInstance) {
|
|
2780
|
+
const formattedMessage = this.formatMessage("error", message, errorContext);
|
|
2781
|
+
process.stderr.write(formattedMessage + "\n");
|
|
2782
|
+
}
|
|
2783
|
+
this.sendToSink("error", message, errorContext).catch(() => {
|
|
2847
2784
|
});
|
|
2848
2785
|
}
|
|
2849
2786
|
}
|
|
@@ -2854,7 +2791,7 @@ var Logger = class _Logger {
|
|
|
2854
2791
|
function createLogger(component, logLevel) {
|
|
2855
2792
|
return new Logger(component, logLevel);
|
|
2856
2793
|
}
|
|
2857
|
-
var logger = createLogger("
|
|
2794
|
+
var logger = createLogger("workflows-core");
|
|
2858
2795
|
|
|
2859
2796
|
// ../core/dist/state-machine-loader.js
|
|
2860
2797
|
var logger2 = createLogger("StateMachineLoader");
|
|
@@ -3080,6 +3017,35 @@ ${continueTransition.additional_instructions}`;
|
|
|
3080
3017
|
}
|
|
3081
3018
|
return stateDefinition.default_instructions;
|
|
3082
3019
|
}
|
|
3020
|
+
/**
|
|
3021
|
+
* Get allowed file patterns for a specific phase.
|
|
3022
|
+
* Returns undefined if no restrictions are defined (all files allowed).
|
|
3023
|
+
*
|
|
3024
|
+
* @param phase - The phase/state name to get patterns for
|
|
3025
|
+
* @returns Array of glob patterns or undefined if all files are allowed
|
|
3026
|
+
*/
|
|
3027
|
+
getAllowedFilePatterns(phase) {
|
|
3028
|
+
if (!this.stateMachine) {
|
|
3029
|
+
throw new Error("State machine not loaded");
|
|
3030
|
+
}
|
|
3031
|
+
const stateDefinition = this.stateMachine.states[phase];
|
|
3032
|
+
if (!stateDefinition) {
|
|
3033
|
+
logger2.error("Unknown phase", new Error(`Unknown phase: ${phase}`));
|
|
3034
|
+
throw new Error(`Unknown phase: ${phase}`);
|
|
3035
|
+
}
|
|
3036
|
+
return stateDefinition.allowed_file_patterns;
|
|
3037
|
+
}
|
|
3038
|
+
/**
|
|
3039
|
+
* Whether the given phase restricts which files may be edited.
|
|
3040
|
+
* Returns false when no allowed_file_patterns are defined (all files allowed).
|
|
3041
|
+
* Callers should use getAllowedFilePatterns + a glob library for actual path matching.
|
|
3042
|
+
*
|
|
3043
|
+
* @param phase - The phase/state name
|
|
3044
|
+
*/
|
|
3045
|
+
hasFileRestrictions(phase) {
|
|
3046
|
+
const patterns = this.getAllowedFilePatterns(phase);
|
|
3047
|
+
return patterns !== void 0 && patterns.length > 0;
|
|
3048
|
+
}
|
|
3083
3049
|
};
|
|
3084
3050
|
|
|
3085
3051
|
// ../core/dist/workflow-manager.js
|
|
@@ -3161,13 +3127,21 @@ var WorkflowManager = class _WorkflowManager {
|
|
|
3161
3127
|
}
|
|
3162
3128
|
/**
|
|
3163
3129
|
* Parse enabled domains from environment variable
|
|
3130
|
+
* Supports both WORKFLOW_DOMAINS and VIBE_WORKFLOW_DOMAINS (legacy)
|
|
3131
|
+
* WORKFLOW_DOMAINS takes precedence if both are set (modern, non-prefixed version preferred)
|
|
3164
3132
|
*/
|
|
3165
3133
|
parseEnabledDomains() {
|
|
3166
|
-
const domainsEnv = process.env["VIBE_WORKFLOW_DOMAINS"];
|
|
3134
|
+
const domainsEnv = process.env["WORKFLOW_DOMAINS"] || process.env["VIBE_WORKFLOW_DOMAINS"];
|
|
3167
3135
|
if (!domainsEnv) {
|
|
3136
|
+
logger4.debug("No domain configuration found, using default: code");
|
|
3168
3137
|
return /* @__PURE__ */ new Set(["code"]);
|
|
3169
3138
|
}
|
|
3170
|
-
|
|
3139
|
+
const domains = new Set(domainsEnv.split(",").map((d) => d.trim()).filter((d) => d));
|
|
3140
|
+
logger4.debug("Parsed enabled domains", {
|
|
3141
|
+
source: process.env["WORKFLOW_DOMAINS"] ? "WORKFLOW_DOMAINS" : "VIBE_WORKFLOW_DOMAINS",
|
|
3142
|
+
domains: Array.from(domains)
|
|
3143
|
+
});
|
|
3144
|
+
return domains;
|
|
3171
3145
|
}
|
|
3172
3146
|
/**
|
|
3173
3147
|
* Load project-specific workflows from .vibe/workflows/
|
|
@@ -3540,16 +3514,21 @@ var WorkflowManager = class _WorkflowManager {
|
|
|
3540
3514
|
}
|
|
3541
3515
|
};
|
|
3542
3516
|
|
|
3517
|
+
// ../core/dist/string-utils.js
|
|
3518
|
+
function capitalizePhase(phase) {
|
|
3519
|
+
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3543
3522
|
// ../core/dist/transition-engine.js
|
|
3544
|
-
var
|
|
3523
|
+
var defaultLogger = createLogger("TransitionEngine");
|
|
3545
3524
|
var TransitionEngine = class {
|
|
3546
|
-
stateMachineLoader;
|
|
3547
3525
|
workflowManager;
|
|
3526
|
+
logger;
|
|
3548
3527
|
conversationManager;
|
|
3549
|
-
constructor(projectPath) {
|
|
3550
|
-
this.stateMachineLoader = new StateMachineLoader();
|
|
3528
|
+
constructor(projectPath, logger24 = defaultLogger) {
|
|
3551
3529
|
this.workflowManager = new WorkflowManager();
|
|
3552
|
-
|
|
3530
|
+
this.logger = logger24;
|
|
3531
|
+
this.logger.info("TransitionEngine initialized", { projectPath });
|
|
3553
3532
|
}
|
|
3554
3533
|
/**
|
|
3555
3534
|
* Set the conversation manager (dependency injection)
|
|
@@ -3568,11 +3547,11 @@ var TransitionEngine = class {
|
|
|
3568
3547
|
*/
|
|
3569
3548
|
async isFirstCallFromInitialState(context) {
|
|
3570
3549
|
if (!this.conversationManager) {
|
|
3571
|
-
|
|
3550
|
+
this.logger.warn("ConversationManager not set, assuming first call");
|
|
3572
3551
|
return true;
|
|
3573
3552
|
}
|
|
3574
3553
|
const hasInteractions = await this.conversationManager.hasInteractions(context.conversationId);
|
|
3575
|
-
|
|
3554
|
+
this.logger.debug("Checking first call from initial state", {
|
|
3576
3555
|
hasInteractions,
|
|
3577
3556
|
conversationId: context.conversationId,
|
|
3578
3557
|
currentPhase: context.currentPhase
|
|
@@ -3582,51 +3561,18 @@ var TransitionEngine = class {
|
|
|
3582
3561
|
/**
|
|
3583
3562
|
* Generate instructions for defining phase entrance criteria
|
|
3584
3563
|
*/
|
|
3585
|
-
|
|
3586
|
-
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
3587
|
-
const workflowName = conversationState?.workflowName;
|
|
3588
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
3564
|
+
generateCriteriaDefinitionInstructions(stateMachine) {
|
|
3589
3565
|
const phases = Object.keys(stateMachine.states);
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
Before we begin development, let's establish clear entrance criteria for each phase. This will help us make informed decisions about when to transition between phases throughout the development process.
|
|
3593
|
-
|
|
3594
|
-
Please update the plan file with a "Phase Entrance Criteria" section that defines specific, measurable criteria for entering each phase:
|
|
3595
|
-
|
|
3596
|
-
## Phase Entrance Criteria
|
|
3597
|
-
|
|
3598
|
-
`;
|
|
3599
|
-
for (const phase of phases) {
|
|
3600
|
-
if (phase === stateMachine.initial_state)
|
|
3601
|
-
continue;
|
|
3602
|
-
const phaseDefinition = stateMachine.states[phase];
|
|
3603
|
-
const capitalizedPhase = this.capitalizePhase(phase);
|
|
3604
|
-
instructions += `### ${capitalizedPhase} Phase
|
|
3605
|
-
*${phaseDefinition.description}*
|
|
3606
|
-
|
|
3607
|
-
**Enter when:**
|
|
3608
|
-
- [ ] [Define specific criteria for entering ${phase} phase]
|
|
3609
|
-
- [ ] [Add measurable conditions that must be met]
|
|
3610
|
-
- [ ] [Include any deliverables or milestones required]
|
|
3611
|
-
|
|
3612
|
-
`;
|
|
3613
|
-
}
|
|
3614
|
-
instructions += `
|
|
3615
|
-
Once you've defined these criteria, we can begin development. Throughout the process, consult these criteria when considering phase transitions.
|
|
3616
|
-
|
|
3617
|
-
**Remember**: These criteria should be specific and measurable so we can clearly determine when each phase is ready to begin.`;
|
|
3618
|
-
return instructions;
|
|
3566
|
+
const phaseList = phases.filter((phase) => phase !== stateMachine.initial_state).map((phase) => capitalizePhase(phase)).join(", ");
|
|
3567
|
+
return `Define entrance criteria for each phase (${phaseList}) in the plan file. Criteria should be specific and measurable.`;
|
|
3619
3568
|
}
|
|
3620
3569
|
/**
|
|
3621
3570
|
* Get phase-specific instructions for continuing work in current phase
|
|
3622
3571
|
*/
|
|
3623
|
-
|
|
3624
|
-
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
3625
|
-
const workflowName = conversationState?.workflowName;
|
|
3626
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
3572
|
+
getContinuePhaseInstructions(phase, stateMachine) {
|
|
3627
3573
|
const stateDefinition = stateMachine.states[phase];
|
|
3628
3574
|
if (!stateDefinition) {
|
|
3629
|
-
|
|
3575
|
+
this.logger.error("Unknown phase", new Error(`Unknown phase: ${phase}`));
|
|
3630
3576
|
throw new Error(`Unknown phase: ${phase}`);
|
|
3631
3577
|
}
|
|
3632
3578
|
const continueTransition = stateDefinition.transitions.find((t) => t.to === phase);
|
|
@@ -3649,19 +3595,17 @@ ${continueTransition.additional_instructions}`;
|
|
|
3649
3595
|
/**
|
|
3650
3596
|
* Get the first development phase from the state machine
|
|
3651
3597
|
*/
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
const workflowName = conversationState?.workflowName;
|
|
3655
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
3656
|
-
const initialState = stateMachine.initial_state;
|
|
3657
|
-
return initialState;
|
|
3598
|
+
getFirstDevelopmentPhase(stateMachine) {
|
|
3599
|
+
return stateMachine.initial_state;
|
|
3658
3600
|
}
|
|
3659
3601
|
/**
|
|
3660
3602
|
* Analyze context and determine appropriate phase transition
|
|
3661
3603
|
*/
|
|
3662
3604
|
async analyzePhaseTransition(context) {
|
|
3663
3605
|
const { currentPhase, projectPath, conversationId, userInput, context: additionalContext, conversationSummary } = context;
|
|
3664
|
-
|
|
3606
|
+
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
3607
|
+
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, conversationState?.workflowName);
|
|
3608
|
+
this.logger.debug("Analyzing phase transition", {
|
|
3665
3609
|
currentPhase,
|
|
3666
3610
|
projectPath,
|
|
3667
3611
|
hasUserInput: !!userInput,
|
|
@@ -3670,14 +3614,14 @@ ${continueTransition.additional_instructions}`;
|
|
|
3670
3614
|
userInput: userInput ? userInput.substring(0, 50) + (userInput.length > 50 ? "..." : "") : void 0
|
|
3671
3615
|
});
|
|
3672
3616
|
if (await this.isFirstCallFromInitialState(context)) {
|
|
3673
|
-
const firstDevelopmentPhase =
|
|
3674
|
-
|
|
3617
|
+
const firstDevelopmentPhase = this.getFirstDevelopmentPhase(stateMachine);
|
|
3618
|
+
this.logger.info("First call from initial state - transitioning to first development phase with criteria", {
|
|
3675
3619
|
currentPhase,
|
|
3676
3620
|
firstDevelopmentPhase,
|
|
3677
3621
|
projectPath
|
|
3678
3622
|
});
|
|
3679
|
-
const criteriaInstructions =
|
|
3680
|
-
const phaseInstructions =
|
|
3623
|
+
const criteriaInstructions = this.generateCriteriaDefinitionInstructions(stateMachine);
|
|
3624
|
+
const phaseInstructions = this.getContinuePhaseInstructions(firstDevelopmentPhase, stateMachine);
|
|
3681
3625
|
return {
|
|
3682
3626
|
newPhase: firstDevelopmentPhase,
|
|
3683
3627
|
// Transition to first development phase
|
|
@@ -3686,8 +3630,8 @@ ${continueTransition.additional_instructions}`;
|
|
|
3686
3630
|
isModeled: true
|
|
3687
3631
|
};
|
|
3688
3632
|
}
|
|
3689
|
-
const continueInstructions =
|
|
3690
|
-
|
|
3633
|
+
const continueInstructions = this.getContinuePhaseInstructions(currentPhase, stateMachine);
|
|
3634
|
+
this.logger.debug("Continuing in current phase - LLM will evaluate transition criteria", {
|
|
3691
3635
|
currentPhase,
|
|
3692
3636
|
projectPath
|
|
3693
3637
|
});
|
|
@@ -3703,7 +3647,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
3703
3647
|
*/
|
|
3704
3648
|
handleExplicitTransition(currentPhase, targetPhase, projectPath, reason, workflowName) {
|
|
3705
3649
|
const stateMachine = this.getStateMachine(projectPath, workflowName);
|
|
3706
|
-
|
|
3650
|
+
this.logger.debug("Handling explicit phase transition", {
|
|
3707
3651
|
currentPhase,
|
|
3708
3652
|
targetPhase,
|
|
3709
3653
|
projectPath,
|
|
@@ -3714,7 +3658,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
3714
3658
|
if (!stateMachine.states[normalizedTargetPhase]) {
|
|
3715
3659
|
const validPhases = Object.keys(stateMachine.states);
|
|
3716
3660
|
const errorMsg = `Invalid target phase: "${targetPhase}". Valid phases are: ${validPhases.join(", ")}`;
|
|
3717
|
-
|
|
3661
|
+
this.logger.error("Invalid target phase", new Error(errorMsg));
|
|
3718
3662
|
throw new Error(errorMsg);
|
|
3719
3663
|
}
|
|
3720
3664
|
const targetState = stateMachine.states[normalizedTargetPhase];
|
|
@@ -3725,7 +3669,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
3725
3669
|
isModeled: false
|
|
3726
3670
|
// Direct phase transitions are not modeled
|
|
3727
3671
|
};
|
|
3728
|
-
|
|
3672
|
+
this.logger.info("Explicit phase transition processed", {
|
|
3729
3673
|
fromPhase: currentPhase,
|
|
3730
3674
|
toPhase: normalizedTargetPhase,
|
|
3731
3675
|
reason: transitionInfo.transitionReason,
|
|
@@ -3738,12 +3682,6 @@ ${continueTransition.additional_instructions}`;
|
|
|
3738
3682
|
isModeled: transitionInfo.isModeled
|
|
3739
3683
|
};
|
|
3740
3684
|
}
|
|
3741
|
-
/**
|
|
3742
|
-
* Capitalize phase name for display
|
|
3743
|
-
*/
|
|
3744
|
-
capitalizePhase(phase) {
|
|
3745
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3746
|
-
}
|
|
3747
3685
|
/**
|
|
3748
3686
|
* Filter transitions based on agent role (for crowd workflows)
|
|
3749
3687
|
* Returns transitions applicable to the current agent
|
|
@@ -3759,7 +3697,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
3759
3697
|
// ../core/dist/file-storage.js
|
|
3760
3698
|
import { promises as fs4 } from "fs";
|
|
3761
3699
|
import { join, dirname } from "path";
|
|
3762
|
-
var
|
|
3700
|
+
var logger5 = createLogger("FileStorage");
|
|
3763
3701
|
var FileStorage = class {
|
|
3764
3702
|
conversationsDir;
|
|
3765
3703
|
basePath;
|
|
@@ -3777,11 +3715,11 @@ var FileStorage = class {
|
|
|
3777
3715
|
async initialize() {
|
|
3778
3716
|
try {
|
|
3779
3717
|
await fs4.mkdir(this.conversationsDir, { recursive: true });
|
|
3780
|
-
|
|
3718
|
+
logger5.debug("FileStorage initialized", {
|
|
3781
3719
|
conversationsDir: this.conversationsDir
|
|
3782
3720
|
});
|
|
3783
3721
|
} catch (error) {
|
|
3784
|
-
|
|
3722
|
+
logger5.error("Failed to initialize FileStorage", error);
|
|
3785
3723
|
throw error;
|
|
3786
3724
|
}
|
|
3787
3725
|
}
|
|
@@ -3831,12 +3769,12 @@ var FileStorage = class {
|
|
|
3831
3769
|
await fs4.mkdir(conversationDir, { recursive: true });
|
|
3832
3770
|
const stateJson = JSON.stringify(state, null, 2);
|
|
3833
3771
|
await this.writeAtomic(stateFilePath, stateJson);
|
|
3834
|
-
|
|
3772
|
+
logger5.debug("Conversation state saved", {
|
|
3835
3773
|
conversationId: state.conversationId,
|
|
3836
3774
|
currentPhase: state.currentPhase
|
|
3837
3775
|
});
|
|
3838
3776
|
} catch (error) {
|
|
3839
|
-
|
|
3777
|
+
logger5.error("Failed to save conversation state", error, {
|
|
3840
3778
|
conversationId: state.conversationId
|
|
3841
3779
|
});
|
|
3842
3780
|
throw error;
|
|
@@ -3856,7 +3794,7 @@ var FileStorage = class {
|
|
|
3856
3794
|
if (error.code === "ENOENT") {
|
|
3857
3795
|
return null;
|
|
3858
3796
|
}
|
|
3859
|
-
|
|
3797
|
+
logger5.warn("Failed to read conversation state, returning null", {
|
|
3860
3798
|
conversationId,
|
|
3861
3799
|
error: error.message
|
|
3862
3800
|
});
|
|
@@ -3888,7 +3826,7 @@ var FileStorage = class {
|
|
|
3888
3826
|
if (error.code === "ENOENT") {
|
|
3889
3827
|
return [];
|
|
3890
3828
|
}
|
|
3891
|
-
|
|
3829
|
+
logger5.error("Failed to get all conversation states", error);
|
|
3892
3830
|
throw error;
|
|
3893
3831
|
}
|
|
3894
3832
|
}
|
|
@@ -3900,13 +3838,13 @@ var FileStorage = class {
|
|
|
3900
3838
|
const conversationDir = this.getConversationDir(conversationId);
|
|
3901
3839
|
try {
|
|
3902
3840
|
await fs4.rm(conversationDir, { recursive: true, force: true });
|
|
3903
|
-
|
|
3841
|
+
logger5.debug("Conversation state deleted", { conversationId });
|
|
3904
3842
|
return true;
|
|
3905
3843
|
} catch (error) {
|
|
3906
3844
|
if (error.code === "ENOENT") {
|
|
3907
3845
|
return false;
|
|
3908
3846
|
}
|
|
3909
|
-
|
|
3847
|
+
logger5.error("Failed to delete conversation state", error, {
|
|
3910
3848
|
conversationId
|
|
3911
3849
|
});
|
|
3912
3850
|
throw error;
|
|
@@ -3923,12 +3861,12 @@ var FileStorage = class {
|
|
|
3923
3861
|
await fs4.mkdir(conversationDir, { recursive: true });
|
|
3924
3862
|
const logLine = JSON.stringify(log) + "\n";
|
|
3925
3863
|
await fs4.appendFile(interactionsFilePath, logLine, "utf-8");
|
|
3926
|
-
|
|
3864
|
+
logger5.debug("Interaction logged", {
|
|
3927
3865
|
conversationId: log.conversationId,
|
|
3928
3866
|
toolName: log.toolName
|
|
3929
3867
|
});
|
|
3930
3868
|
} catch (error) {
|
|
3931
|
-
|
|
3869
|
+
logger5.error("Failed to log interaction", error, {
|
|
3932
3870
|
conversationId: log.conversationId,
|
|
3933
3871
|
toolName: log.toolName
|
|
3934
3872
|
});
|
|
@@ -3950,7 +3888,7 @@ var FileStorage = class {
|
|
|
3950
3888
|
const log = JSON.parse(line);
|
|
3951
3889
|
logs.push(log);
|
|
3952
3890
|
} catch {
|
|
3953
|
-
|
|
3891
|
+
logger5.warn("Skipping corrupted interaction log line", {
|
|
3954
3892
|
conversationId
|
|
3955
3893
|
});
|
|
3956
3894
|
}
|
|
@@ -3960,7 +3898,7 @@ var FileStorage = class {
|
|
|
3960
3898
|
if (error.code === "ENOENT") {
|
|
3961
3899
|
return [];
|
|
3962
3900
|
}
|
|
3963
|
-
|
|
3901
|
+
logger5.error("Failed to get interaction logs", error, {
|
|
3964
3902
|
conversationId
|
|
3965
3903
|
});
|
|
3966
3904
|
throw error;
|
|
@@ -3980,12 +3918,12 @@ var FileStorage = class {
|
|
|
3980
3918
|
const interactionsFilePath = this.getInteractionsFilePath(conversationId);
|
|
3981
3919
|
try {
|
|
3982
3920
|
await fs4.unlink(interactionsFilePath);
|
|
3983
|
-
|
|
3921
|
+
logger5.debug("Interaction logs deleted", { conversationId });
|
|
3984
3922
|
} catch (error) {
|
|
3985
3923
|
if (error.code === "ENOENT") {
|
|
3986
3924
|
return;
|
|
3987
3925
|
}
|
|
3988
|
-
|
|
3926
|
+
logger5.warn("Failed to delete interaction logs", {
|
|
3989
3927
|
conversationId,
|
|
3990
3928
|
error: error.message
|
|
3991
3929
|
});
|
|
@@ -4004,13 +3942,13 @@ var FileStorage = class {
|
|
|
4004
3942
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4005
3943
|
};
|
|
4006
3944
|
await this.saveConversationState(updatedState);
|
|
4007
|
-
|
|
3945
|
+
logger5.debug("Conversation state reset", { conversationId });
|
|
4008
3946
|
}
|
|
4009
3947
|
/**
|
|
4010
3948
|
* Close file storage (no-op for file-based storage)
|
|
4011
3949
|
*/
|
|
4012
3950
|
async close() {
|
|
4013
|
-
|
|
3951
|
+
logger5.debug("FileStorage closed");
|
|
4014
3952
|
}
|
|
4015
3953
|
};
|
|
4016
3954
|
|
|
@@ -4022,7 +3960,7 @@ import { existsSync } from "fs";
|
|
|
4022
3960
|
// ../core/dist/path-validation-utils.js
|
|
4023
3961
|
import { access, stat } from "fs/promises";
|
|
4024
3962
|
import { resolve, isAbsolute, join as join2, normalize, basename } from "path";
|
|
4025
|
-
var
|
|
3963
|
+
var logger6 = createLogger("PathValidationUtils");
|
|
4026
3964
|
var PathValidationUtils = class {
|
|
4027
3965
|
/**
|
|
4028
3966
|
* Validate if a string is a known template name
|
|
@@ -4050,7 +3988,7 @@ var PathValidationUtils = class {
|
|
|
4050
3988
|
error: "Path points to a directory, not a file"
|
|
4051
3989
|
};
|
|
4052
3990
|
}
|
|
4053
|
-
|
|
3991
|
+
logger6.debug("File path validated successfully", {
|
|
4054
3992
|
originalPath: filePath,
|
|
4055
3993
|
resolvedPath
|
|
4056
3994
|
});
|
|
@@ -4060,7 +3998,7 @@ var PathValidationUtils = class {
|
|
|
4060
3998
|
};
|
|
4061
3999
|
} catch (error) {
|
|
4062
4000
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
4063
|
-
|
|
4001
|
+
logger6.debug("File path validation failed", {
|
|
4064
4002
|
filePath,
|
|
4065
4003
|
error: errorMessage
|
|
4066
4004
|
});
|
|
@@ -4090,7 +4028,7 @@ var PathValidationUtils = class {
|
|
|
4090
4028
|
error: "Path is neither a file nor a directory"
|
|
4091
4029
|
};
|
|
4092
4030
|
}
|
|
4093
|
-
|
|
4031
|
+
logger6.debug("File or directory path validated successfully", {
|
|
4094
4032
|
originalPath: filePath,
|
|
4095
4033
|
resolvedPath,
|
|
4096
4034
|
isFile: stats.isFile(),
|
|
@@ -4102,7 +4040,7 @@ var PathValidationUtils = class {
|
|
|
4102
4040
|
};
|
|
4103
4041
|
} catch (error) {
|
|
4104
4042
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
4105
|
-
|
|
4043
|
+
logger6.debug("File or directory path validation failed", {
|
|
4106
4044
|
filePath,
|
|
4107
4045
|
error: errorMessage
|
|
4108
4046
|
});
|
|
@@ -4217,7 +4155,7 @@ function getPathBasename(filePath, fallback = "unknown") {
|
|
|
4217
4155
|
import { writeFile, readFile, access as access2 } from "fs/promises";
|
|
4218
4156
|
import { dirname as dirname2 } from "path";
|
|
4219
4157
|
import { mkdir } from "fs/promises";
|
|
4220
|
-
var
|
|
4158
|
+
var logger7 = createLogger("PlanManager");
|
|
4221
4159
|
var PlanManager = class {
|
|
4222
4160
|
stateMachine = null;
|
|
4223
4161
|
/**
|
|
@@ -4225,7 +4163,7 @@ var PlanManager = class {
|
|
|
4225
4163
|
*/
|
|
4226
4164
|
setStateMachine(stateMachine) {
|
|
4227
4165
|
this.stateMachine = stateMachine;
|
|
4228
|
-
|
|
4166
|
+
logger7.debug("State machine set for plan manager", {
|
|
4229
4167
|
name: stateMachine.name,
|
|
4230
4168
|
phases: Object.keys(stateMachine.states)
|
|
4231
4169
|
});
|
|
@@ -4234,7 +4172,7 @@ var PlanManager = class {
|
|
|
4234
4172
|
* Set the task backend configuration
|
|
4235
4173
|
*/
|
|
4236
4174
|
setTaskBackend(taskBackend) {
|
|
4237
|
-
|
|
4175
|
+
logger7.debug("Task backend set for plan manager (markdown mode)", {
|
|
4238
4176
|
backend: taskBackend.backend,
|
|
4239
4177
|
available: taskBackend.isAvailable
|
|
4240
4178
|
});
|
|
@@ -4262,43 +4200,43 @@ var PlanManager = class {
|
|
|
4262
4200
|
* Create initial plan file if it doesn't exist
|
|
4263
4201
|
*/
|
|
4264
4202
|
async ensurePlanFile(planFilePath, projectPath, gitBranch) {
|
|
4265
|
-
|
|
4203
|
+
logger7.debug("Ensuring plan file exists", {
|
|
4266
4204
|
planFilePath,
|
|
4267
4205
|
projectPath,
|
|
4268
4206
|
gitBranch
|
|
4269
4207
|
});
|
|
4270
4208
|
const planInfo = await this.getPlanFileInfo(planFilePath);
|
|
4271
4209
|
if (!planInfo.exists) {
|
|
4272
|
-
|
|
4210
|
+
logger7.info("Plan file not found, creating initial plan", {
|
|
4273
4211
|
planFilePath
|
|
4274
4212
|
});
|
|
4275
4213
|
await this.createInitialPlanFile(planFilePath, projectPath, gitBranch);
|
|
4276
|
-
|
|
4214
|
+
logger7.info("Initial plan file created successfully", { planFilePath });
|
|
4277
4215
|
} else {
|
|
4278
|
-
|
|
4216
|
+
logger7.debug("Plan file already exists", { planFilePath });
|
|
4279
4217
|
}
|
|
4280
4218
|
}
|
|
4281
4219
|
/**
|
|
4282
4220
|
* Create initial plan file with template content
|
|
4283
4221
|
*/
|
|
4284
4222
|
async createInitialPlanFile(planFilePath, projectPath, gitBranch) {
|
|
4285
|
-
|
|
4223
|
+
logger7.debug("Creating initial plan file", { planFilePath });
|
|
4286
4224
|
try {
|
|
4287
4225
|
await mkdir(dirname2(planFilePath), { recursive: true });
|
|
4288
|
-
|
|
4226
|
+
logger7.debug("Plan file directory ensured", {
|
|
4289
4227
|
directory: dirname2(planFilePath)
|
|
4290
4228
|
});
|
|
4291
4229
|
const projectName = getPathBasename(projectPath, "Unknown Project");
|
|
4292
4230
|
const branchInfo = gitBranch !== "no-git" ? ` (${gitBranch} branch)` : "";
|
|
4293
4231
|
const initialContent = this.generateInitialPlanContent(projectName, branchInfo);
|
|
4294
4232
|
await writeFile(planFilePath, initialContent, "utf-8");
|
|
4295
|
-
|
|
4233
|
+
logger7.info("Initial plan file written successfully", {
|
|
4296
4234
|
planFilePath,
|
|
4297
4235
|
contentLength: initialContent.length,
|
|
4298
4236
|
projectName
|
|
4299
4237
|
});
|
|
4300
4238
|
} catch (error) {
|
|
4301
|
-
|
|
4239
|
+
logger7.error("Failed to create initial plan file", error, {
|
|
4302
4240
|
planFilePath
|
|
4303
4241
|
});
|
|
4304
4242
|
throw error;
|
|
@@ -4330,7 +4268,7 @@ var PlanManager = class {
|
|
|
4330
4268
|
*Additional context and observations*
|
|
4331
4269
|
|
|
4332
4270
|
`;
|
|
4333
|
-
content += `## ${
|
|
4271
|
+
content += `## ${capitalizePhase(initialPhase)}
|
|
4334
4272
|
### Tasks
|
|
4335
4273
|
- [ ] *Tasks will be added as they are identified*
|
|
4336
4274
|
|
|
@@ -4340,7 +4278,7 @@ var PlanManager = class {
|
|
|
4340
4278
|
`;
|
|
4341
4279
|
for (const phase of phases) {
|
|
4342
4280
|
if (phase !== initialPhase) {
|
|
4343
|
-
content += `## ${
|
|
4281
|
+
content += `## ${capitalizePhase(phase)}
|
|
4344
4282
|
### Tasks
|
|
4345
4283
|
- [ ] *To be added when this phase becomes active*
|
|
4346
4284
|
|
|
@@ -4392,31 +4330,31 @@ var PlanManager = class {
|
|
|
4392
4330
|
}
|
|
4393
4331
|
const phaseDefinition = this.stateMachine.states[phase];
|
|
4394
4332
|
if (!phaseDefinition) {
|
|
4395
|
-
|
|
4396
|
-
return `Update the ${
|
|
4333
|
+
logger7.warn("Unknown phase for plan file guidance", { phase });
|
|
4334
|
+
return `Update the ${capitalizePhase(phase)} section with current progress and mark completed tasks.`;
|
|
4397
4335
|
}
|
|
4398
|
-
const capitalizedPhase =
|
|
4336
|
+
const capitalizedPhase = capitalizePhase(phase);
|
|
4399
4337
|
return `Update the ${capitalizedPhase} section with progress. Mark completed tasks with [x] and add new tasks as they are identified.`;
|
|
4400
4338
|
}
|
|
4401
4339
|
/**
|
|
4402
4340
|
* Delete plan file
|
|
4403
4341
|
*/
|
|
4404
4342
|
async deletePlanFile(planFilePath) {
|
|
4405
|
-
|
|
4343
|
+
logger7.debug("Deleting plan file", { planFilePath });
|
|
4406
4344
|
try {
|
|
4407
4345
|
await access2(planFilePath);
|
|
4408
4346
|
const { unlink: unlink2 } = await import("fs/promises");
|
|
4409
4347
|
await unlink2(planFilePath);
|
|
4410
|
-
|
|
4348
|
+
logger7.info("Plan file deleted successfully", { planFilePath });
|
|
4411
4349
|
return true;
|
|
4412
4350
|
} catch (error) {
|
|
4413
4351
|
if (error.code === "ENOENT") {
|
|
4414
|
-
|
|
4352
|
+
logger7.debug("Plan file does not exist, nothing to delete", {
|
|
4415
4353
|
planFilePath
|
|
4416
4354
|
});
|
|
4417
4355
|
return true;
|
|
4418
4356
|
}
|
|
4419
|
-
|
|
4357
|
+
logger7.error("Failed to delete plan file", error, {
|
|
4420
4358
|
planFilePath
|
|
4421
4359
|
});
|
|
4422
4360
|
throw error;
|
|
@@ -4426,32 +4364,26 @@ var PlanManager = class {
|
|
|
4426
4364
|
* Ensure plan file is deleted (verify deletion)
|
|
4427
4365
|
*/
|
|
4428
4366
|
async ensurePlanFileDeleted(planFilePath) {
|
|
4429
|
-
|
|
4367
|
+
logger7.debug("Ensuring plan file is deleted", { planFilePath });
|
|
4430
4368
|
try {
|
|
4431
4369
|
await access2(planFilePath);
|
|
4432
|
-
|
|
4370
|
+
logger7.warn("Plan file still exists after deletion attempt", {
|
|
4433
4371
|
planFilePath
|
|
4434
4372
|
});
|
|
4435
4373
|
return false;
|
|
4436
4374
|
} catch (error) {
|
|
4437
4375
|
if (error.code === "ENOENT") {
|
|
4438
|
-
|
|
4376
|
+
logger7.debug("Plan file successfully deleted (does not exist)", {
|
|
4439
4377
|
planFilePath
|
|
4440
4378
|
});
|
|
4441
4379
|
return true;
|
|
4442
4380
|
}
|
|
4443
|
-
|
|
4381
|
+
logger7.error("Error checking plan file deletion", error, {
|
|
4444
4382
|
planFilePath
|
|
4445
4383
|
});
|
|
4446
4384
|
throw error;
|
|
4447
4385
|
}
|
|
4448
4386
|
}
|
|
4449
|
-
/**
|
|
4450
|
-
* Capitalize phase name for display
|
|
4451
|
-
*/
|
|
4452
|
-
capitalizePhase(phase) {
|
|
4453
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
4454
|
-
}
|
|
4455
4387
|
/**
|
|
4456
4388
|
* Generate workflow documentation URL for predefined workflows
|
|
4457
4389
|
* Returns undefined for custom workflows
|
|
@@ -4462,10 +4394,24 @@ var PlanManager = class {
|
|
|
4462
4394
|
}
|
|
4463
4395
|
return `https://mrsimpson.github.io/responsible-vibe-mcp/workflows/${workflowName}`;
|
|
4464
4396
|
}
|
|
4397
|
+
/**
|
|
4398
|
+
* Generate base instructions for the LLM after a workflow is started.
|
|
4399
|
+
* Instructs the LLM to populate the Goal section and define phase entrance
|
|
4400
|
+
* criteria in the freshly created plan file.
|
|
4401
|
+
*/
|
|
4402
|
+
getInitialPlanGuidance(planFilePath, workflowDocUrl) {
|
|
4403
|
+
const docInfo = workflowDocUrl ? `
|
|
4404
|
+
|
|
4405
|
+
Inform the user about the chosen workflow. They can visit: ${workflowDocUrl} to get detailed information.` : "";
|
|
4406
|
+
const i18nNote = `
|
|
4407
|
+
|
|
4408
|
+
NOTE: If the user is communicating in a non-English language, translate plan file content to that language while keeping markdown headers (##, ###) in English to maintain structure parsing. Continue all interactions in the user's language.`;
|
|
4409
|
+
return `**Read ${planFilePath}** to understand the workflow structure. Add entrance criteria for each phase (what must be true to enter), then call \`whats_next()\`.${docInfo}${i18nNote}`;
|
|
4410
|
+
}
|
|
4465
4411
|
};
|
|
4466
4412
|
|
|
4467
4413
|
// ../core/dist/conversation-manager.js
|
|
4468
|
-
var
|
|
4414
|
+
var logger8 = createLogger("ConversationManager");
|
|
4469
4415
|
var ConversationManager = class {
|
|
4470
4416
|
database;
|
|
4471
4417
|
projectPath;
|
|
@@ -4492,11 +4438,11 @@ var ConversationManager = class {
|
|
|
4492
4438
|
async getConversationContext() {
|
|
4493
4439
|
const projectPath = this.getProjectPath();
|
|
4494
4440
|
const gitBranch = this.getGitBranch(projectPath);
|
|
4495
|
-
|
|
4441
|
+
logger8.debug("Getting conversation context", { projectPath, gitBranch });
|
|
4496
4442
|
const conversationId = this.generateConversationId(projectPath, gitBranch);
|
|
4497
4443
|
const state = await this.database.getConversationState(conversationId);
|
|
4498
4444
|
if (!state) {
|
|
4499
|
-
|
|
4445
|
+
logger8.warn("No conversation found for context", {
|
|
4500
4446
|
projectPath,
|
|
4501
4447
|
gitBranch,
|
|
4502
4448
|
conversationId
|
|
@@ -4525,7 +4471,7 @@ var ConversationManager = class {
|
|
|
4525
4471
|
async createConversationContext(workflowName, projectPathOverride) {
|
|
4526
4472
|
const projectPath = projectPathOverride || this.getProjectPath();
|
|
4527
4473
|
const gitBranch = this.getGitBranch(projectPath);
|
|
4528
|
-
|
|
4474
|
+
logger8.debug("Creating conversation context", {
|
|
4529
4475
|
projectPath,
|
|
4530
4476
|
gitBranch,
|
|
4531
4477
|
workflowName
|
|
@@ -4535,14 +4481,14 @@ var ConversationManager = class {
|
|
|
4535
4481
|
if (existingState) {
|
|
4536
4482
|
if (existingState.workflowName !== workflowName) {
|
|
4537
4483
|
const errorMessage = `Development conversation already exists with workflow '${existingState.workflowName}'. Cannot change to '${workflowName}'. Use reset_development() first to start with a new workflow.`;
|
|
4538
|
-
|
|
4484
|
+
logger8.error("Attempted workflow change on existing conversation", new Error(errorMessage), {
|
|
4539
4485
|
existingWorkflow: existingState.workflowName,
|
|
4540
4486
|
requestedWorkflow: workflowName,
|
|
4541
4487
|
conversationId
|
|
4542
4488
|
});
|
|
4543
4489
|
throw new Error(errorMessage);
|
|
4544
4490
|
}
|
|
4545
|
-
|
|
4491
|
+
logger8.debug("Conversation already exists, returning existing context", {
|
|
4546
4492
|
conversationId
|
|
4547
4493
|
});
|
|
4548
4494
|
return {
|
|
@@ -4571,7 +4517,7 @@ var ConversationManager = class {
|
|
|
4571
4517
|
* @param updates - Partial state updates to apply
|
|
4572
4518
|
*/
|
|
4573
4519
|
async updateConversationState(conversationId, updates) {
|
|
4574
|
-
|
|
4520
|
+
logger8.debug("Updating conversation state", { conversationId, updates });
|
|
4575
4521
|
const currentState = await this.database.getConversationState(conversationId);
|
|
4576
4522
|
if (!currentState) {
|
|
4577
4523
|
throw new Error(`Conversation state not found for ID: ${conversationId}`);
|
|
@@ -4582,7 +4528,7 @@ var ConversationManager = class {
|
|
|
4582
4528
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4583
4529
|
};
|
|
4584
4530
|
await this.database.saveConversationState(updatedState);
|
|
4585
|
-
|
|
4531
|
+
logger8.info("Conversation state updated", {
|
|
4586
4532
|
conversationId,
|
|
4587
4533
|
currentPhase: updatedState.currentPhase
|
|
4588
4534
|
});
|
|
@@ -4595,7 +4541,7 @@ var ConversationManager = class {
|
|
|
4595
4541
|
* @param gitBranch - Git branch name
|
|
4596
4542
|
*/
|
|
4597
4543
|
async createNewConversationState(conversationId, projectPath, gitBranch, workflowName = "waterfall") {
|
|
4598
|
-
|
|
4544
|
+
logger8.info("Creating new conversation state", {
|
|
4599
4545
|
conversationId,
|
|
4600
4546
|
projectPath,
|
|
4601
4547
|
gitBranch
|
|
@@ -4619,7 +4565,7 @@ var ConversationManager = class {
|
|
|
4619
4565
|
updatedAt: timestamp2
|
|
4620
4566
|
};
|
|
4621
4567
|
await this.database.saveConversationState(newState);
|
|
4622
|
-
|
|
4568
|
+
logger8.info("New conversation state created", {
|
|
4623
4569
|
conversationId,
|
|
4624
4570
|
planFilePath,
|
|
4625
4571
|
initialPhase
|
|
@@ -4662,7 +4608,7 @@ var ConversationManager = class {
|
|
|
4662
4608
|
getGitBranch(projectPath) {
|
|
4663
4609
|
try {
|
|
4664
4610
|
if (!existsSync(`${projectPath}/.git`)) {
|
|
4665
|
-
|
|
4611
|
+
logger8.debug('Not a git repository, using "default" as branch name', {
|
|
4666
4612
|
projectPath
|
|
4667
4613
|
});
|
|
4668
4614
|
return "default";
|
|
@@ -4673,10 +4619,10 @@ var ConversationManager = class {
|
|
|
4673
4619
|
stdio: ["ignore", "pipe", "ignore"]
|
|
4674
4620
|
// Suppress stderr
|
|
4675
4621
|
}).trim();
|
|
4676
|
-
|
|
4622
|
+
logger8.debug("Detected git branch", { projectPath, branch });
|
|
4677
4623
|
return branch;
|
|
4678
4624
|
} catch (_error) {
|
|
4679
|
-
|
|
4625
|
+
logger8.debug('Failed to get git branch, using "default" as branch name', {
|
|
4680
4626
|
projectPath
|
|
4681
4627
|
});
|
|
4682
4628
|
return "default";
|
|
@@ -4690,13 +4636,13 @@ var ConversationManager = class {
|
|
|
4690
4636
|
try {
|
|
4691
4637
|
const interactions = await this.database.getInteractionsByConversationId(conversationId);
|
|
4692
4638
|
const count = interactions.length;
|
|
4693
|
-
|
|
4639
|
+
logger8.debug("Checked interaction count for conversation", {
|
|
4694
4640
|
conversationId,
|
|
4695
4641
|
count
|
|
4696
4642
|
});
|
|
4697
4643
|
return count > 0;
|
|
4698
4644
|
} catch (error) {
|
|
4699
|
-
|
|
4645
|
+
logger8.error("Failed to check interaction count", error, {
|
|
4700
4646
|
conversationId
|
|
4701
4647
|
});
|
|
4702
4648
|
return false;
|
|
@@ -4706,24 +4652,24 @@ var ConversationManager = class {
|
|
|
4706
4652
|
* Reset conversation data (hybrid approach)
|
|
4707
4653
|
*/
|
|
4708
4654
|
async resetConversation(confirm, reason) {
|
|
4709
|
-
|
|
4655
|
+
logger8.info("Starting conversation reset", { confirm, reason });
|
|
4710
4656
|
this.validateResetRequest(confirm);
|
|
4711
4657
|
const context = await this.getConversationContext();
|
|
4712
4658
|
const resetItems = [];
|
|
4713
4659
|
try {
|
|
4714
4660
|
await this.database.softDeleteInteractionLogs(context.conversationId);
|
|
4715
4661
|
resetItems.push("interaction_logs");
|
|
4716
|
-
|
|
4662
|
+
logger8.debug("Interaction logs soft deleted");
|
|
4717
4663
|
await this.database.deleteConversationState(context.conversationId);
|
|
4718
4664
|
resetItems.push("conversation_state");
|
|
4719
|
-
|
|
4665
|
+
logger8.debug("Conversation state hard deleted");
|
|
4720
4666
|
const planManager = new PlanManager();
|
|
4721
4667
|
await planManager.deletePlanFile(context.planFilePath);
|
|
4722
4668
|
resetItems.push("plan_file");
|
|
4723
|
-
|
|
4669
|
+
logger8.debug("Plan file deleted");
|
|
4724
4670
|
await this.verifyResetCleanup(context.conversationId, context.planFilePath);
|
|
4725
4671
|
const message = `Successfully reset conversation ${context.conversationId}. Reset items: ${resetItems.join(", ")}${reason ? `. Reason: ${reason}` : ""}`;
|
|
4726
|
-
|
|
4672
|
+
logger8.info("Conversation reset completed successfully", {
|
|
4727
4673
|
conversationId: context.conversationId,
|
|
4728
4674
|
resetItems,
|
|
4729
4675
|
reason
|
|
@@ -4735,7 +4681,7 @@ var ConversationManager = class {
|
|
|
4735
4681
|
message
|
|
4736
4682
|
};
|
|
4737
4683
|
} catch (error) {
|
|
4738
|
-
|
|
4684
|
+
logger8.error("Failed to reset conversation", error, {
|
|
4739
4685
|
conversationId: context.conversationId,
|
|
4740
4686
|
resetItems,
|
|
4741
4687
|
reason
|
|
@@ -4755,7 +4701,7 @@ var ConversationManager = class {
|
|
|
4755
4701
|
* Verify that reset cleanup was successful
|
|
4756
4702
|
*/
|
|
4757
4703
|
async verifyResetCleanup(conversationId, planFilePath) {
|
|
4758
|
-
|
|
4704
|
+
logger8.debug("Verifying reset cleanup", { conversationId, planFilePath });
|
|
4759
4705
|
try {
|
|
4760
4706
|
const state = await this.database.getConversationState(conversationId);
|
|
4761
4707
|
if (state) {
|
|
@@ -4766,9 +4712,9 @@ var ConversationManager = class {
|
|
|
4766
4712
|
if (!isDeleted) {
|
|
4767
4713
|
throw new Error("Plan file was not properly deleted");
|
|
4768
4714
|
}
|
|
4769
|
-
|
|
4715
|
+
logger8.debug("Reset cleanup verification successful");
|
|
4770
4716
|
} catch (error) {
|
|
4771
|
-
|
|
4717
|
+
logger8.error("Reset cleanup verification failed", error);
|
|
4772
4718
|
throw error;
|
|
4773
4719
|
}
|
|
4774
4720
|
}
|
|
@@ -4776,13 +4722,13 @@ var ConversationManager = class {
|
|
|
4776
4722
|
* Clean up conversation data (used internally)
|
|
4777
4723
|
*/
|
|
4778
4724
|
async cleanupConversationData(conversationId) {
|
|
4779
|
-
|
|
4725
|
+
logger8.debug("Cleaning up conversation data", { conversationId });
|
|
4780
4726
|
try {
|
|
4781
4727
|
await this.database.softDeleteInteractionLogs(conversationId);
|
|
4782
4728
|
await this.database.deleteConversationState(conversationId);
|
|
4783
|
-
|
|
4729
|
+
logger8.debug("Conversation data cleanup completed", { conversationId });
|
|
4784
4730
|
} catch (error) {
|
|
4785
|
-
|
|
4731
|
+
logger8.error("Failed to cleanup conversation data", error, {
|
|
4786
4732
|
conversationId
|
|
4787
4733
|
});
|
|
4788
4734
|
throw error;
|
|
@@ -4795,7 +4741,7 @@ import { readFile as readFile2, readdir, stat as stat2 } from "fs/promises";
|
|
|
4795
4741
|
import { join as join3, dirname as dirname3 } from "path";
|
|
4796
4742
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4797
4743
|
import { createRequire as createRequire3 } from "module";
|
|
4798
|
-
var
|
|
4744
|
+
var logger9 = createLogger("TemplateManager");
|
|
4799
4745
|
var TemplateManager = class {
|
|
4800
4746
|
templatesPath;
|
|
4801
4747
|
constructor() {
|
|
@@ -4824,13 +4770,13 @@ var TemplateManager = class {
|
|
|
4824
4770
|
for (const strategy of strategies) {
|
|
4825
4771
|
try {
|
|
4826
4772
|
__require("fs").accessSync(strategy);
|
|
4827
|
-
|
|
4773
|
+
logger9.debug("Using templates path", { path: strategy });
|
|
4828
4774
|
return strategy;
|
|
4829
4775
|
} catch (_error) {
|
|
4830
4776
|
}
|
|
4831
4777
|
}
|
|
4832
4778
|
const fallback = strategies[0];
|
|
4833
|
-
|
|
4779
|
+
logger9.warn("No templates directory found, using fallback", {
|
|
4834
4780
|
fallback,
|
|
4835
4781
|
strategies
|
|
4836
4782
|
});
|
|
@@ -4884,7 +4830,7 @@ var TemplateManager = class {
|
|
|
4884
4830
|
const content = await readFile2(templateFilePath, "utf-8");
|
|
4885
4831
|
return { content };
|
|
4886
4832
|
} catch (error) {
|
|
4887
|
-
|
|
4833
|
+
logger9.error(`Failed to load template: ${type2}/${template}`, error);
|
|
4888
4834
|
throw new Error(`Template not found: ${type2}/${template}. Tried: ${templatePath} (directory) and ${templateFilePath} (file)`);
|
|
4889
4835
|
}
|
|
4890
4836
|
}
|
|
@@ -4965,16 +4911,16 @@ var TemplateManager = class {
|
|
|
4965
4911
|
}
|
|
4966
4912
|
templates.sort();
|
|
4967
4913
|
} catch (error) {
|
|
4968
|
-
|
|
4914
|
+
logger9.warn(`Failed to scan templates for type: ${type2}`, {
|
|
4969
4915
|
typePath,
|
|
4970
4916
|
error: error instanceof Error ? error.message : String(error)
|
|
4971
4917
|
});
|
|
4972
4918
|
}
|
|
4973
4919
|
}
|
|
4974
|
-
|
|
4920
|
+
logger9.debug("Discovered available templates", result);
|
|
4975
4921
|
return result;
|
|
4976
4922
|
} catch (error) {
|
|
4977
|
-
|
|
4923
|
+
logger9.error("Failed to discover templates", error);
|
|
4978
4924
|
return result;
|
|
4979
4925
|
}
|
|
4980
4926
|
}
|
|
@@ -4983,12 +4929,14 @@ var TemplateManager = class {
|
|
|
4983
4929
|
// ../core/dist/project-docs-manager.js
|
|
4984
4930
|
import { writeFile as writeFile2, access as access3, mkdir as mkdir2, unlink, symlink, lstat, stat as stat3, readdir as readdir2 } from "fs/promises";
|
|
4985
4931
|
import { join as join4, dirname as dirname4, relative, extname, basename as basename2 } from "path";
|
|
4986
|
-
var
|
|
4932
|
+
var defaultLogger2 = createLogger("ProjectDocsManager");
|
|
4987
4933
|
var ProjectDocsManager = class {
|
|
4988
4934
|
templateManager;
|
|
4989
4935
|
// Make public for access from other classes
|
|
4990
|
-
|
|
4936
|
+
logger;
|
|
4937
|
+
constructor(logger24 = defaultLogger2) {
|
|
4991
4938
|
this.templateManager = new TemplateManager();
|
|
4939
|
+
this.logger = logger24;
|
|
4992
4940
|
}
|
|
4993
4941
|
/**
|
|
4994
4942
|
* Get project docs directory path
|
|
@@ -5159,7 +5107,7 @@ var ProjectDocsManager = class {
|
|
|
5159
5107
|
} else {
|
|
5160
5108
|
skipped.push("design.md");
|
|
5161
5109
|
}
|
|
5162
|
-
|
|
5110
|
+
this.logger.info("Project docs creation/linking completed", {
|
|
5163
5111
|
created,
|
|
5164
5112
|
linked,
|
|
5165
5113
|
skipped,
|
|
@@ -5178,13 +5126,13 @@ var ProjectDocsManager = class {
|
|
|
5178
5126
|
const targetDir = dirname4(targetPath);
|
|
5179
5127
|
const relativePath = relative(targetDir, sourcePath);
|
|
5180
5128
|
await symlink(relativePath, targetPath);
|
|
5181
|
-
|
|
5129
|
+
this.logger.debug("Symlink created successfully", {
|
|
5182
5130
|
sourcePath,
|
|
5183
5131
|
targetPath,
|
|
5184
5132
|
relativePath
|
|
5185
5133
|
});
|
|
5186
5134
|
} catch (error) {
|
|
5187
|
-
|
|
5135
|
+
this.logger.error("Failed to create symlink", error, {
|
|
5188
5136
|
sourcePath,
|
|
5189
5137
|
targetPath
|
|
5190
5138
|
});
|
|
@@ -5198,14 +5146,14 @@ var ProjectDocsManager = class {
|
|
|
5198
5146
|
try {
|
|
5199
5147
|
const stats = await lstat(documentPath);
|
|
5200
5148
|
await unlink(documentPath);
|
|
5201
|
-
|
|
5149
|
+
this.logger.debug("Existing document removed", {
|
|
5202
5150
|
documentPath,
|
|
5203
5151
|
wasSymlink: stats.isSymbolicLink()
|
|
5204
5152
|
});
|
|
5205
5153
|
} catch (error) {
|
|
5206
5154
|
const nodeError = error;
|
|
5207
5155
|
if (error instanceof Error && "code" in nodeError && nodeError.code !== "ENOENT") {
|
|
5208
|
-
|
|
5156
|
+
this.logger.debug("Failed to remove existing document", {
|
|
5209
5157
|
documentPath,
|
|
5210
5158
|
error: nodeError.message
|
|
5211
5159
|
});
|
|
@@ -5227,9 +5175,9 @@ var ProjectDocsManager = class {
|
|
|
5227
5175
|
await writeFile2(filePath, file.content.toString());
|
|
5228
5176
|
}
|
|
5229
5177
|
}
|
|
5230
|
-
|
|
5178
|
+
this.logger.debug(`Created ${type2} document`, { documentPath, template });
|
|
5231
5179
|
} catch (error) {
|
|
5232
|
-
|
|
5180
|
+
this.logger.error(`Failed to create ${type2} document`, error, {
|
|
5233
5181
|
documentPath,
|
|
5234
5182
|
template
|
|
5235
5183
|
});
|
|
@@ -5300,12 +5248,12 @@ var ProjectDocsManager = class {
|
|
|
5300
5248
|
// ../core/dist/file-detection-manager.js
|
|
5301
5249
|
import { readdir as readdir3, access as access4 } from "fs/promises";
|
|
5302
5250
|
import { join as join5, basename as basename3 } from "path";
|
|
5303
|
-
var
|
|
5251
|
+
var logger10 = createLogger("FileDetectionManager");
|
|
5304
5252
|
|
|
5305
5253
|
// ../core/dist/git-manager.js
|
|
5306
5254
|
import { execSync as execSync2 } from "child_process";
|
|
5307
5255
|
import { existsSync as existsSync2 } from "fs";
|
|
5308
|
-
var
|
|
5256
|
+
var logger11 = createLogger("GitManager");
|
|
5309
5257
|
var GitManager = class {
|
|
5310
5258
|
/**
|
|
5311
5259
|
* Check if a directory is a git repository
|
|
@@ -5319,7 +5267,7 @@ var GitManager = class {
|
|
|
5319
5267
|
static getCurrentBranch(projectPath) {
|
|
5320
5268
|
try {
|
|
5321
5269
|
if (!this.isGitRepository(projectPath)) {
|
|
5322
|
-
|
|
5270
|
+
logger11.debug('Not a git repository, using "default" as branch name', {
|
|
5323
5271
|
projectPath
|
|
5324
5272
|
});
|
|
5325
5273
|
return "default";
|
|
@@ -5329,10 +5277,10 @@ var GitManager = class {
|
|
|
5329
5277
|
encoding: "utf-8",
|
|
5330
5278
|
stdio: ["ignore", "pipe", "ignore"]
|
|
5331
5279
|
}).trim();
|
|
5332
|
-
|
|
5280
|
+
logger11.debug("Detected git branch", { projectPath, branch });
|
|
5333
5281
|
return branch;
|
|
5334
5282
|
} catch (_error) {
|
|
5335
|
-
|
|
5283
|
+
logger11.debug('Failed to get git branch, using "default" as branch name', {
|
|
5336
5284
|
projectPath
|
|
5337
5285
|
});
|
|
5338
5286
|
return "default";
|
|
@@ -5353,7 +5301,7 @@ var GitManager = class {
|
|
|
5353
5301
|
}).trim();
|
|
5354
5302
|
return hash;
|
|
5355
5303
|
} catch (error) {
|
|
5356
|
-
|
|
5304
|
+
logger11.debug("Failed to get current commit hash", { projectPath, error });
|
|
5357
5305
|
return null;
|
|
5358
5306
|
}
|
|
5359
5307
|
}
|
|
@@ -5363,7 +5311,7 @@ var GitManager = class {
|
|
|
5363
5311
|
static createCommit(message, projectPath) {
|
|
5364
5312
|
try {
|
|
5365
5313
|
if (!this.isGitRepository(projectPath)) {
|
|
5366
|
-
|
|
5314
|
+
logger11.debug("Not a git repository, skipping commit", { projectPath });
|
|
5367
5315
|
return false;
|
|
5368
5316
|
}
|
|
5369
5317
|
execSync2("git add .", {
|
|
@@ -5376,10 +5324,10 @@ var GitManager = class {
|
|
|
5376
5324
|
encoding: "utf-8",
|
|
5377
5325
|
stdio: ["ignore", "pipe", "ignore"]
|
|
5378
5326
|
});
|
|
5379
|
-
|
|
5327
|
+
logger11.debug("Created commit successfully", { projectPath, message });
|
|
5380
5328
|
return true;
|
|
5381
5329
|
} catch (error) {
|
|
5382
|
-
|
|
5330
|
+
logger11.debug("Failed to create commit", {
|
|
5383
5331
|
projectPath,
|
|
5384
5332
|
message,
|
|
5385
5333
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -5393,7 +5341,7 @@ var GitManager = class {
|
|
|
5393
5341
|
static hasUncommittedChanges(projectPath) {
|
|
5394
5342
|
try {
|
|
5395
5343
|
if (!this.isGitRepository(projectPath)) {
|
|
5396
|
-
|
|
5344
|
+
logger11.debug("Not a git repository, no uncommitted changes", {
|
|
5397
5345
|
projectPath
|
|
5398
5346
|
});
|
|
5399
5347
|
return false;
|
|
@@ -5404,13 +5352,13 @@ var GitManager = class {
|
|
|
5404
5352
|
stdio: ["ignore", "pipe", "ignore"]
|
|
5405
5353
|
}).trim();
|
|
5406
5354
|
const hasChanges = status.length > 0;
|
|
5407
|
-
|
|
5355
|
+
logger11.debug("Checked for uncommitted changes", {
|
|
5408
5356
|
projectPath,
|
|
5409
5357
|
hasChanges
|
|
5410
5358
|
});
|
|
5411
5359
|
return hasChanges;
|
|
5412
5360
|
} catch (error) {
|
|
5413
|
-
|
|
5361
|
+
logger11.debug("Failed to check for uncommitted changes", {
|
|
5414
5362
|
projectPath,
|
|
5415
5363
|
error: error instanceof Error ? error.message : String(error)
|
|
5416
5364
|
});
|
|
@@ -5421,7 +5369,7 @@ var GitManager = class {
|
|
|
5421
5369
|
|
|
5422
5370
|
// ../core/dist/task-backend.js
|
|
5423
5371
|
import { execSync as execSync3 } from "child_process";
|
|
5424
|
-
var
|
|
5372
|
+
var defaultLogger3 = createLogger("TaskBackend");
|
|
5425
5373
|
var TaskBackendManager = class _TaskBackendManager {
|
|
5426
5374
|
/**
|
|
5427
5375
|
* Detect and validate the requested task backend
|
|
@@ -5433,18 +5381,19 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5433
5381
|
* When TASK_BACKEND is explicitly set:
|
|
5434
5382
|
* - Uses the specified backend (markdown or beads)
|
|
5435
5383
|
* - For beads, validates availability and provides setup instructions if not available
|
|
5384
|
+
*
|
|
5436
5385
|
*/
|
|
5437
|
-
static detectTaskBackend() {
|
|
5386
|
+
static detectTaskBackend(logger24 = defaultLogger3) {
|
|
5438
5387
|
const envBackend = process.env["TASK_BACKEND"]?.toLowerCase().trim();
|
|
5439
5388
|
if (envBackend && !["markdown", "beads"].includes(envBackend)) {
|
|
5440
|
-
|
|
5389
|
+
logger24.debug("Invalid TASK_BACKEND value, treating as not set", {
|
|
5441
5390
|
envBackend
|
|
5442
5391
|
});
|
|
5443
5392
|
}
|
|
5444
5393
|
if (!envBackend || !["markdown", "beads"].includes(envBackend)) {
|
|
5445
|
-
const beadsAvailable2 = _TaskBackendManager.checkBeadsAvailability();
|
|
5394
|
+
const beadsAvailable2 = _TaskBackendManager.checkBeadsAvailability(logger24);
|
|
5446
5395
|
if (beadsAvailable2.isAvailable) {
|
|
5447
|
-
|
|
5396
|
+
logger24.debug("Auto-detected beads backend (bd command available)", {
|
|
5448
5397
|
reason: "TASK_BACKEND not set, bd command found"
|
|
5449
5398
|
});
|
|
5450
5399
|
return {
|
|
@@ -5452,7 +5401,7 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5452
5401
|
isAvailable: true
|
|
5453
5402
|
};
|
|
5454
5403
|
}
|
|
5455
|
-
|
|
5404
|
+
logger24.debug("Using markdown backend (bd command not available)", {
|
|
5456
5405
|
reason: "TASK_BACKEND not set, bd command not found"
|
|
5457
5406
|
});
|
|
5458
5407
|
return {
|
|
@@ -5462,15 +5411,15 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5462
5411
|
}
|
|
5463
5412
|
const backend = envBackend;
|
|
5464
5413
|
if (backend === "markdown") {
|
|
5465
|
-
|
|
5414
|
+
logger24.debug("Using explicitly configured markdown backend");
|
|
5466
5415
|
return {
|
|
5467
5416
|
backend: "markdown",
|
|
5468
5417
|
isAvailable: true
|
|
5469
5418
|
};
|
|
5470
5419
|
}
|
|
5471
|
-
const beadsAvailable = _TaskBackendManager.checkBeadsAvailability();
|
|
5420
|
+
const beadsAvailable = _TaskBackendManager.checkBeadsAvailability(logger24);
|
|
5472
5421
|
if (beadsAvailable.isAvailable) {
|
|
5473
|
-
|
|
5422
|
+
logger24.debug("Using explicitly configured beads backend");
|
|
5474
5423
|
return {
|
|
5475
5424
|
backend: "beads",
|
|
5476
5425
|
isAvailable: true
|
|
@@ -5485,14 +5434,14 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5485
5434
|
/**
|
|
5486
5435
|
* Check if beads command is available and functional
|
|
5487
5436
|
*/
|
|
5488
|
-
static checkBeadsAvailability() {
|
|
5437
|
+
static checkBeadsAvailability(logger24 = defaultLogger3) {
|
|
5489
5438
|
try {
|
|
5490
5439
|
const output = execSync3("bd --version", {
|
|
5491
5440
|
encoding: "utf-8",
|
|
5492
5441
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5493
5442
|
timeout: 5e3
|
|
5494
5443
|
});
|
|
5495
|
-
|
|
5444
|
+
logger24.debug("Beads command available", { version: output.trim() });
|
|
5496
5445
|
return { isAvailable: true };
|
|
5497
5446
|
} catch (error) {
|
|
5498
5447
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -5508,7 +5457,7 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5508
5457
|
errorMessage: "Beads command (bd) timed out. Check if beads is properly installed and configured."
|
|
5509
5458
|
};
|
|
5510
5459
|
}
|
|
5511
|
-
|
|
5460
|
+
logger24.warn("Beads availability check failed", { errorMessage });
|
|
5512
5461
|
return {
|
|
5513
5462
|
isAvailable: false,
|
|
5514
5463
|
errorMessage: `Beads command (bd) check failed: ${errorMessage}`
|
|
@@ -5561,9 +5510,10 @@ export TASK_BACKEND=markdown
|
|
|
5561
5510
|
}
|
|
5562
5511
|
/**
|
|
5563
5512
|
* Validate task backend configuration and throw error if invalid
|
|
5513
|
+
*
|
|
5564
5514
|
*/
|
|
5565
|
-
static validateTaskBackend() {
|
|
5566
|
-
const config = this.detectTaskBackend();
|
|
5515
|
+
static validateTaskBackend(logger24 = defaultLogger3) {
|
|
5516
|
+
const config = this.detectTaskBackend(logger24);
|
|
5567
5517
|
if (!config.isAvailable) {
|
|
5568
5518
|
const setupInstructions = config.backend === "beads" ? this.getBeadsSetupInstructions() : "Task backend validation failed";
|
|
5569
5519
|
throw new Error(`Task backend '${config.backend}' is not available.
|
|
@@ -5572,7 +5522,7 @@ ${config.errorMessage || ""}
|
|
|
5572
5522
|
|
|
5573
5523
|
${setupInstructions}`);
|
|
5574
5524
|
}
|
|
5575
|
-
|
|
5525
|
+
logger24.info("Task backend validated successfully", {
|
|
5576
5526
|
backend: config.backend,
|
|
5577
5527
|
available: config.isAvailable
|
|
5578
5528
|
});
|
|
@@ -5582,11 +5532,13 @@ ${setupInstructions}`);
|
|
|
5582
5532
|
|
|
5583
5533
|
// ../core/dist/beads-integration.js
|
|
5584
5534
|
import { execSync as execSync4 } from "child_process";
|
|
5585
|
-
var
|
|
5535
|
+
var defaultLogger4 = createLogger("BeadsIntegration");
|
|
5586
5536
|
var BeadsIntegration = class {
|
|
5587
5537
|
projectPath;
|
|
5588
|
-
|
|
5538
|
+
logger;
|
|
5539
|
+
constructor(projectPath, logger24 = defaultLogger4) {
|
|
5589
5540
|
this.projectPath = projectPath;
|
|
5541
|
+
this.logger = logger24;
|
|
5590
5542
|
}
|
|
5591
5543
|
/**
|
|
5592
5544
|
* Ensure beads is initialized in the project directory
|
|
@@ -5602,7 +5554,7 @@ var BeadsIntegration = class {
|
|
|
5602
5554
|
} catch (error) {
|
|
5603
5555
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5604
5556
|
if (errorMessage.includes("not initialized") || errorMessage.includes("no database") || errorMessage.includes("init")) {
|
|
5605
|
-
|
|
5557
|
+
this.logger.info("Beads not initialized, running bd init --no-db", {
|
|
5606
5558
|
projectPath: this.projectPath
|
|
5607
5559
|
});
|
|
5608
5560
|
try {
|
|
@@ -5611,12 +5563,12 @@ var BeadsIntegration = class {
|
|
|
5611
5563
|
encoding: "utf-8",
|
|
5612
5564
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5613
5565
|
});
|
|
5614
|
-
|
|
5566
|
+
this.logger.info("Successfully initialized beads in project", {
|
|
5615
5567
|
projectPath: this.projectPath
|
|
5616
5568
|
});
|
|
5617
5569
|
} catch (initError) {
|
|
5618
5570
|
const initErrorMessage = initError instanceof Error ? initError.message : String(initError);
|
|
5619
|
-
|
|
5571
|
+
this.logger.error("Failed to initialize beads", initError instanceof Error ? initError : new Error(initErrorMessage), { projectPath: this.projectPath });
|
|
5620
5572
|
throw new Error(`Failed to initialize beads: ${initErrorMessage}`);
|
|
5621
5573
|
}
|
|
5622
5574
|
} else {
|
|
@@ -5634,7 +5586,7 @@ var BeadsIntegration = class {
|
|
|
5634
5586
|
const epicDescription = description || `Responsible vibe engineering session using ${workflowName} workflow for ${projectName}`;
|
|
5635
5587
|
const priority = 2;
|
|
5636
5588
|
const command = `bd create "${epicTitle}" --description "${epicDescription}" --priority ${priority}`;
|
|
5637
|
-
|
|
5589
|
+
this.logger.debug("Creating beads project epic", {
|
|
5638
5590
|
command,
|
|
5639
5591
|
projectName,
|
|
5640
5592
|
workflowName,
|
|
@@ -5648,7 +5600,7 @@ var BeadsIntegration = class {
|
|
|
5648
5600
|
});
|
|
5649
5601
|
const match = output.match(/✓ Created issue: ([\w\d.-]+)/) || output.match(/Created issue: ([\w\d.-]+)/) || output.match(/Created (bd-[\w\d.]+)/);
|
|
5650
5602
|
if (!match) {
|
|
5651
|
-
|
|
5603
|
+
this.logger.warn("Failed to extract task ID from beads output", {
|
|
5652
5604
|
command: `bd create "${epicTitle}" --description "${epicDescription}" --priority 2`,
|
|
5653
5605
|
output: output.slice(0, 200)
|
|
5654
5606
|
// Truncated for logging
|
|
@@ -5656,7 +5608,7 @@ var BeadsIntegration = class {
|
|
|
5656
5608
|
throw new Error(`Failed to extract task ID from beads output: ${output.slice(0, 100)}...`);
|
|
5657
5609
|
}
|
|
5658
5610
|
const epicId = match[1] || "";
|
|
5659
|
-
|
|
5611
|
+
this.logger.info("Created beads project epic", {
|
|
5660
5612
|
epicId,
|
|
5661
5613
|
epicTitle,
|
|
5662
5614
|
projectPath: this.projectPath
|
|
@@ -5670,10 +5622,10 @@ var BeadsIntegration = class {
|
|
|
5670
5622
|
workflowName,
|
|
5671
5623
|
projectPath: this.projectPath
|
|
5672
5624
|
};
|
|
5673
|
-
|
|
5625
|
+
this.logger.error("Failed to create beads project epic", error instanceof Error ? error : new Error(errorMessage), commandInfo);
|
|
5674
5626
|
const execError = error;
|
|
5675
5627
|
if (execError?.stderr) {
|
|
5676
|
-
|
|
5628
|
+
this.logger.error("Beads command stderr output", new Error("Command stderr"), {
|
|
5677
5629
|
stderr: execError.stderr.toString(),
|
|
5678
5630
|
...commandInfo
|
|
5679
5631
|
});
|
|
@@ -5689,12 +5641,12 @@ var BeadsIntegration = class {
|
|
|
5689
5641
|
const phaseTasks = [];
|
|
5690
5642
|
const phaseNames = Object.keys(phases);
|
|
5691
5643
|
for (const phase of phaseNames) {
|
|
5692
|
-
const phaseTitle =
|
|
5644
|
+
const phaseTitle = capitalizePhase(phase);
|
|
5693
5645
|
const priority = 3;
|
|
5694
5646
|
const stateDefinition = phases[phase];
|
|
5695
5647
|
const description = (stateDefinition?.default_instructions || `${workflowName} workflow ${phase} phase tasks`).replace(/"/g, '\\"').replace(/\n/g, " ").replace(/\r/g, "").trim();
|
|
5696
5648
|
const command = `bd create "${phaseTitle}" --description "${description}" --parent ${epicId} --priority ${priority}`;
|
|
5697
|
-
|
|
5649
|
+
this.logger.debug("Creating beads phase task", {
|
|
5698
5650
|
command,
|
|
5699
5651
|
phase,
|
|
5700
5652
|
epicId,
|
|
@@ -5708,7 +5660,7 @@ var BeadsIntegration = class {
|
|
|
5708
5660
|
});
|
|
5709
5661
|
const match = output.match(/✓ Created issue: ([\w\d.-]+)/) || output.match(/Created issue: ([\w\d.-]+)/) || output.match(/Created (bd-[\w\d.]+)/);
|
|
5710
5662
|
if (!match) {
|
|
5711
|
-
|
|
5663
|
+
this.logger.warn("Failed to extract phase task ID from beads output", {
|
|
5712
5664
|
command,
|
|
5713
5665
|
output: output.slice(0, 200)
|
|
5714
5666
|
// Truncated for logging
|
|
@@ -5721,7 +5673,7 @@ var BeadsIntegration = class {
|
|
|
5721
5673
|
phaseName: phaseTitle,
|
|
5722
5674
|
taskId: phaseTaskId
|
|
5723
5675
|
});
|
|
5724
|
-
|
|
5676
|
+
this.logger.debug("Created beads phase task", {
|
|
5725
5677
|
phase,
|
|
5726
5678
|
phaseTaskId,
|
|
5727
5679
|
epicId,
|
|
@@ -5735,10 +5687,10 @@ var BeadsIntegration = class {
|
|
|
5735
5687
|
epicId,
|
|
5736
5688
|
projectPath: this.projectPath
|
|
5737
5689
|
};
|
|
5738
|
-
|
|
5690
|
+
this.logger.error("Failed to create beads phase task", error instanceof Error ? error : new Error(errorMessage), commandInfo);
|
|
5739
5691
|
const execError = error;
|
|
5740
5692
|
if (execError?.stderr) {
|
|
5741
|
-
|
|
5693
|
+
this.logger.error("Beads phase command stderr output", new Error("Command stderr"), {
|
|
5742
5694
|
stderr: execError.stderr.toString(),
|
|
5743
5695
|
...commandInfo
|
|
5744
5696
|
});
|
|
@@ -5746,7 +5698,7 @@ var BeadsIntegration = class {
|
|
|
5746
5698
|
throw new Error(`Failed to create beads phase task for ${phase}: ${errorMessage}`);
|
|
5747
5699
|
}
|
|
5748
5700
|
}
|
|
5749
|
-
|
|
5701
|
+
this.logger.info("Created all beads phase tasks", {
|
|
5750
5702
|
count: phaseTasks.length,
|
|
5751
5703
|
epicId,
|
|
5752
5704
|
projectPath: this.projectPath
|
|
@@ -5759,13 +5711,13 @@ var BeadsIntegration = class {
|
|
|
5759
5711
|
*/
|
|
5760
5712
|
async createPhaseDependencies(phaseTasks) {
|
|
5761
5713
|
if (phaseTasks.length < 2) {
|
|
5762
|
-
|
|
5714
|
+
this.logger.debug("Skipping phase dependencies - less than 2 phases", {
|
|
5763
5715
|
phaseCount: phaseTasks.length,
|
|
5764
5716
|
projectPath: this.projectPath
|
|
5765
5717
|
});
|
|
5766
5718
|
return;
|
|
5767
5719
|
}
|
|
5768
|
-
|
|
5720
|
+
this.logger.info("Creating sequential phase dependencies", {
|
|
5769
5721
|
phaseCount: phaseTasks.length,
|
|
5770
5722
|
projectPath: this.projectPath
|
|
5771
5723
|
});
|
|
@@ -5774,7 +5726,7 @@ var BeadsIntegration = class {
|
|
|
5774
5726
|
const currentPhase = phaseTasks[i];
|
|
5775
5727
|
const nextPhase = phaseTasks[i + 1];
|
|
5776
5728
|
if (!currentPhase || !nextPhase) {
|
|
5777
|
-
|
|
5729
|
+
this.logger.warn("Skipping phase dependency - missing phase data", {
|
|
5778
5730
|
currentPhaseIndex: i,
|
|
5779
5731
|
nextPhaseIndex: i + 1,
|
|
5780
5732
|
totalPhases: phaseTasks.length,
|
|
@@ -5788,7 +5740,7 @@ var BeadsIntegration = class {
|
|
|
5788
5740
|
continue;
|
|
5789
5741
|
}
|
|
5790
5742
|
const command = `bd dep ${currentPhase.taskId} --blocks ${nextPhase.taskId}`;
|
|
5791
|
-
|
|
5743
|
+
this.logger.debug("Creating phase dependency", {
|
|
5792
5744
|
command,
|
|
5793
5745
|
currentPhase: currentPhase.phaseName,
|
|
5794
5746
|
nextPhase: nextPhase.phaseName,
|
|
@@ -5802,14 +5754,14 @@ var BeadsIntegration = class {
|
|
|
5802
5754
|
encoding: "utf-8",
|
|
5803
5755
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5804
5756
|
});
|
|
5805
|
-
|
|
5757
|
+
this.logger.debug("Successfully created phase dependency", {
|
|
5806
5758
|
currentPhase: currentPhase.phaseName,
|
|
5807
5759
|
nextPhase: nextPhase.phaseName,
|
|
5808
5760
|
projectPath: this.projectPath
|
|
5809
5761
|
});
|
|
5810
5762
|
} catch (error) {
|
|
5811
5763
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5812
|
-
|
|
5764
|
+
this.logger.warn("Failed to create phase dependency - continuing anyway", {
|
|
5813
5765
|
error: errorMessage,
|
|
5814
5766
|
command,
|
|
5815
5767
|
currentPhase: currentPhase.phaseName,
|
|
@@ -5818,7 +5770,7 @@ var BeadsIntegration = class {
|
|
|
5818
5770
|
});
|
|
5819
5771
|
const execError = error;
|
|
5820
5772
|
if (execError?.stderr) {
|
|
5821
|
-
|
|
5773
|
+
this.logger.debug("Beads dependency command stderr", {
|
|
5822
5774
|
stderr: execError.stderr.toString(),
|
|
5823
5775
|
command,
|
|
5824
5776
|
projectPath: this.projectPath
|
|
@@ -5832,25 +5784,19 @@ var BeadsIntegration = class {
|
|
|
5832
5784
|
}
|
|
5833
5785
|
}
|
|
5834
5786
|
if (failedDependencies.length > 0) {
|
|
5835
|
-
|
|
5787
|
+
this.logger.warn("Some phase dependencies could not be created - app continues without these dependencies", {
|
|
5836
5788
|
failedCount: failedDependencies.length,
|
|
5837
5789
|
failedDependencies,
|
|
5838
5790
|
projectPath: this.projectPath
|
|
5839
5791
|
});
|
|
5840
5792
|
}
|
|
5841
|
-
|
|
5793
|
+
this.logger.info("Completed phase dependency creation", {
|
|
5842
5794
|
dependencyCount: phaseTasks.length - 1,
|
|
5843
5795
|
successCount: phaseTasks.length - 1 - failedDependencies.length,
|
|
5844
5796
|
failedCount: failedDependencies.length,
|
|
5845
5797
|
projectPath: this.projectPath
|
|
5846
5798
|
});
|
|
5847
5799
|
}
|
|
5848
|
-
/**
|
|
5849
|
-
* Capitalize phase name for display
|
|
5850
|
-
*/
|
|
5851
|
-
capitalizePhase(phase) {
|
|
5852
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
5853
|
-
}
|
|
5854
5800
|
/**
|
|
5855
5801
|
* Validate parameters for epic creation
|
|
5856
5802
|
*/
|
|
@@ -5898,11 +5844,13 @@ var BeadsIntegration = class {
|
|
|
5898
5844
|
// ../core/dist/beads-state-manager.js
|
|
5899
5845
|
import { writeFile as writeFile3, readFile as readFile3, mkdir as mkdir3, access as access5 } from "fs/promises";
|
|
5900
5846
|
import { join as join6, dirname as dirname5 } from "path";
|
|
5901
|
-
var
|
|
5847
|
+
var defaultLogger5 = createLogger("BeadsStateManager");
|
|
5902
5848
|
var BeadsStateManager = class {
|
|
5903
5849
|
projectPath;
|
|
5904
|
-
|
|
5850
|
+
logger;
|
|
5851
|
+
constructor(projectPath, logger24 = defaultLogger5) {
|
|
5905
5852
|
this.projectPath = projectPath;
|
|
5853
|
+
this.logger = logger24;
|
|
5906
5854
|
}
|
|
5907
5855
|
/**
|
|
5908
5856
|
* Get the path to the beads state file for a conversation
|
|
@@ -5923,7 +5871,7 @@ var BeadsStateManager = class {
|
|
|
5923
5871
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5924
5872
|
};
|
|
5925
5873
|
await this.saveState(state);
|
|
5926
|
-
|
|
5874
|
+
this.logger.info("Created beads conversation state", {
|
|
5927
5875
|
conversationId,
|
|
5928
5876
|
epicId,
|
|
5929
5877
|
phaseCount: phaseTasks.length,
|
|
@@ -5940,7 +5888,7 @@ var BeadsStateManager = class {
|
|
|
5940
5888
|
await access5(statePath);
|
|
5941
5889
|
const content = await readFile3(statePath, "utf-8");
|
|
5942
5890
|
const state = JSON.parse(content);
|
|
5943
|
-
|
|
5891
|
+
this.logger.debug("Retrieved beads conversation state", {
|
|
5944
5892
|
conversationId,
|
|
5945
5893
|
epicId: state.epicId,
|
|
5946
5894
|
phaseCount: state.phaseTasks.length,
|
|
@@ -5949,14 +5897,14 @@ var BeadsStateManager = class {
|
|
|
5949
5897
|
return state;
|
|
5950
5898
|
} catch (error) {
|
|
5951
5899
|
if (error.code === "ENOENT") {
|
|
5952
|
-
|
|
5900
|
+
this.logger.debug("No beads state found for conversation", {
|
|
5953
5901
|
conversationId,
|
|
5954
5902
|
projectPath: this.projectPath
|
|
5955
5903
|
});
|
|
5956
5904
|
return null;
|
|
5957
5905
|
}
|
|
5958
5906
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
5959
|
-
|
|
5907
|
+
this.logger.warn("Failed to read beads state file", {
|
|
5960
5908
|
error: errorMessage,
|
|
5961
5909
|
conversationId,
|
|
5962
5910
|
statePath,
|
|
@@ -5975,7 +5923,7 @@ var BeadsStateManager = class {
|
|
|
5975
5923
|
}
|
|
5976
5924
|
const phaseTask = state.phaseTasks.find((task) => task.phaseId === phase);
|
|
5977
5925
|
if (phaseTask) {
|
|
5978
|
-
|
|
5926
|
+
this.logger.debug("Found phase task ID", {
|
|
5979
5927
|
conversationId,
|
|
5980
5928
|
phase,
|
|
5981
5929
|
taskId: phaseTask.taskId,
|
|
@@ -5983,7 +5931,7 @@ var BeadsStateManager = class {
|
|
|
5983
5931
|
});
|
|
5984
5932
|
return phaseTask.taskId;
|
|
5985
5933
|
}
|
|
5986
|
-
|
|
5934
|
+
this.logger.debug("No task ID found for phase", {
|
|
5987
5935
|
conversationId,
|
|
5988
5936
|
phase,
|
|
5989
5937
|
availablePhases: state.phaseTasks.map((t) => t.phaseId),
|
|
@@ -5997,7 +5945,7 @@ var BeadsStateManager = class {
|
|
|
5997
5945
|
async updateState(conversationId, updates) {
|
|
5998
5946
|
const existingState = await this.getState(conversationId);
|
|
5999
5947
|
if (!existingState) {
|
|
6000
|
-
|
|
5948
|
+
this.logger.warn("Cannot update non-existent beads state", {
|
|
6001
5949
|
conversationId,
|
|
6002
5950
|
projectPath: this.projectPath
|
|
6003
5951
|
});
|
|
@@ -6011,7 +5959,7 @@ var BeadsStateManager = class {
|
|
|
6011
5959
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6012
5960
|
};
|
|
6013
5961
|
await this.saveState(updatedState);
|
|
6014
|
-
|
|
5962
|
+
this.logger.info("Updated beads conversation state", {
|
|
6015
5963
|
conversationId,
|
|
6016
5964
|
updatedFields: Object.keys(updates),
|
|
6017
5965
|
projectPath: this.projectPath
|
|
@@ -6026,21 +5974,21 @@ var BeadsStateManager = class {
|
|
|
6026
5974
|
try {
|
|
6027
5975
|
await access5(statePath);
|
|
6028
5976
|
await writeFile3(statePath + ".backup", await readFile3(statePath));
|
|
6029
|
-
|
|
5977
|
+
this.logger.info("Cleaned up beads conversation state", {
|
|
6030
5978
|
conversationId,
|
|
6031
5979
|
statePath,
|
|
6032
5980
|
projectPath: this.projectPath
|
|
6033
5981
|
});
|
|
6034
5982
|
} catch (error) {
|
|
6035
5983
|
if (error.code === "ENOENT") {
|
|
6036
|
-
|
|
5984
|
+
this.logger.debug("No beads state to clean up", {
|
|
6037
5985
|
conversationId,
|
|
6038
5986
|
projectPath: this.projectPath
|
|
6039
5987
|
});
|
|
6040
5988
|
return;
|
|
6041
5989
|
}
|
|
6042
5990
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6043
|
-
|
|
5991
|
+
this.logger.warn("Failed to clean up beads state", {
|
|
6044
5992
|
error: errorMessage,
|
|
6045
5993
|
conversationId,
|
|
6046
5994
|
statePath,
|
|
@@ -6070,7 +6018,7 @@ var BeadsStateManager = class {
|
|
|
6070
6018
|
await mkdir3(stateDir, { recursive: true });
|
|
6071
6019
|
const content = JSON.stringify(state, null, 2);
|
|
6072
6020
|
await writeFile3(statePath, content, "utf-8");
|
|
6073
|
-
|
|
6021
|
+
this.logger.debug("Saved beads state to file", {
|
|
6074
6022
|
conversationId: state.conversationId,
|
|
6075
6023
|
statePath,
|
|
6076
6024
|
fileSize: content.length,
|
|
@@ -6078,7 +6026,7 @@ var BeadsStateManager = class {
|
|
|
6078
6026
|
});
|
|
6079
6027
|
} catch (error) {
|
|
6080
6028
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6081
|
-
|
|
6029
|
+
this.logger.error("Failed to save beads state", error instanceof Error ? error : new Error(errorMessage), {
|
|
6082
6030
|
conversationId: state.conversationId,
|
|
6083
6031
|
statePath,
|
|
6084
6032
|
projectPath: this.projectPath
|
|
@@ -6089,7 +6037,7 @@ var BeadsStateManager = class {
|
|
|
6089
6037
|
};
|
|
6090
6038
|
|
|
6091
6039
|
// ../core/dist/interaction-logger.js
|
|
6092
|
-
var
|
|
6040
|
+
var logger12 = createLogger("InteractionLogger");
|
|
6093
6041
|
var InteractionLogger = class {
|
|
6094
6042
|
database;
|
|
6095
6043
|
/**
|
|
@@ -6099,7 +6047,7 @@ var InteractionLogger = class {
|
|
|
6099
6047
|
*/
|
|
6100
6048
|
constructor(database) {
|
|
6101
6049
|
this.database = database;
|
|
6102
|
-
|
|
6050
|
+
logger12.debug("InteractionLogger initialized");
|
|
6103
6051
|
}
|
|
6104
6052
|
/**
|
|
6105
6053
|
* Log an interaction with a tool
|
|
@@ -6112,7 +6060,7 @@ var InteractionLogger = class {
|
|
|
6112
6060
|
* @returns Promise that resolves when the log is saved
|
|
6113
6061
|
*/
|
|
6114
6062
|
async logInteraction(conversationId, toolName, inputParams, responseData, currentPhase) {
|
|
6115
|
-
|
|
6063
|
+
logger12.debug("Logging interaction", {
|
|
6116
6064
|
conversationId,
|
|
6117
6065
|
toolName,
|
|
6118
6066
|
currentPhase
|
|
@@ -6128,13 +6076,13 @@ var InteractionLogger = class {
|
|
|
6128
6076
|
timestamp: timestamp2
|
|
6129
6077
|
};
|
|
6130
6078
|
await this.database.logInteraction(log);
|
|
6131
|
-
|
|
6079
|
+
logger12.info("Interaction logged successfully", {
|
|
6132
6080
|
conversationId,
|
|
6133
6081
|
toolName,
|
|
6134
6082
|
timestamp: timestamp2
|
|
6135
6083
|
});
|
|
6136
6084
|
} catch (error) {
|
|
6137
|
-
|
|
6085
|
+
logger12.error("Failed to log interaction", error, {
|
|
6138
6086
|
conversationId,
|
|
6139
6087
|
toolName
|
|
6140
6088
|
});
|
|
@@ -6147,16 +6095,16 @@ var InteractionLogger = class {
|
|
|
6147
6095
|
* @returns Promise that resolves to an array of interaction logs
|
|
6148
6096
|
*/
|
|
6149
6097
|
async getInteractionsByConversationId(conversationId) {
|
|
6150
|
-
|
|
6098
|
+
logger12.debug("Getting interactions by conversation ID", { conversationId });
|
|
6151
6099
|
try {
|
|
6152
6100
|
const logs = await this.database.getInteractionsByConversationId(conversationId);
|
|
6153
|
-
|
|
6101
|
+
logger12.info("Retrieved interaction logs", {
|
|
6154
6102
|
conversationId,
|
|
6155
6103
|
count: logs.length
|
|
6156
6104
|
});
|
|
6157
6105
|
return logs;
|
|
6158
6106
|
} catch (error) {
|
|
6159
|
-
|
|
6107
|
+
logger12.error("Failed to get interaction logs", error, {
|
|
6160
6108
|
conversationId
|
|
6161
6109
|
});
|
|
6162
6110
|
throw error;
|
|
@@ -6167,11 +6115,11 @@ var InteractionLogger = class {
|
|
|
6167
6115
|
// ../core/dist/instruction-generator.js
|
|
6168
6116
|
var InstructionGenerator = class {
|
|
6169
6117
|
projectDocsManager;
|
|
6170
|
-
constructor(
|
|
6171
|
-
this.projectDocsManager = new ProjectDocsManager();
|
|
6118
|
+
constructor(logger24 = createLogger("InstructionGenerator")) {
|
|
6119
|
+
this.projectDocsManager = new ProjectDocsManager(logger24);
|
|
6172
6120
|
}
|
|
6173
6121
|
/**
|
|
6174
|
-
*
|
|
6122
|
+
* No-op: all phase context is provided per-call via InstructionContext.
|
|
6175
6123
|
*/
|
|
6176
6124
|
setStateMachine(_stateMachine) {
|
|
6177
6125
|
return;
|
|
@@ -6184,7 +6132,6 @@ var InstructionGenerator = class {
|
|
|
6184
6132
|
const enhancedInstructions = await this.enhanceInstructions(substitutedInstructions, context);
|
|
6185
6133
|
return {
|
|
6186
6134
|
instructions: enhancedInstructions,
|
|
6187
|
-
planFileGuidance: "Task management guidance is now included in main instructions",
|
|
6188
6135
|
metadata: {
|
|
6189
6136
|
phase: context.phase,
|
|
6190
6137
|
planFilePath: context.conversationContext.planFilePath,
|
|
@@ -6215,43 +6162,36 @@ var InstructionGenerator = class {
|
|
|
6215
6162
|
* Enhance base instructions with context-specific information
|
|
6216
6163
|
*/
|
|
6217
6164
|
async enhanceInstructions(baseInstructions, context) {
|
|
6218
|
-
const { phase, conversationContext,
|
|
6219
|
-
const phaseName =
|
|
6165
|
+
const { phase, conversationContext, allowedFilePatterns } = context;
|
|
6166
|
+
const phaseName = capitalizePhase(phase);
|
|
6220
6167
|
let workflowSection = `---
|
|
6221
|
-
**
|
|
6222
|
-
|
|
6223
|
-
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
workflowSection += "\n\nCall `whats_next()` after each user message.";
|
|
6168
|
+
**Read \`${conversationContext.planFilePath}\`** for context.
|
|
6169
|
+
- Focus on "${phaseName}" tasks, log decisions in "Key Decisions"
|
|
6170
|
+
- Do NOT use other task/todo tools - use only the plan file for task tracking`;
|
|
6171
|
+
if (allowedFilePatterns && allowedFilePatterns.length > 0 && !allowedFilePatterns.includes("**/*") && !allowedFilePatterns.includes("*")) {
|
|
6172
|
+
workflowSection += `
|
|
6173
|
+
- Files allowed: \`${allowedFilePatterns.join("`, `")}\``;
|
|
6174
|
+
}
|
|
6175
|
+
workflowSection += "\n\nCall `whats_next()` after user messages.";
|
|
6230
6176
|
return `## ${phaseName} Phase
|
|
6231
6177
|
|
|
6232
6178
|
${baseInstructions}
|
|
6233
6179
|
|
|
6234
6180
|
${workflowSection}`;
|
|
6235
6181
|
}
|
|
6236
|
-
/**
|
|
6237
|
-
* Capitalize phase name for display
|
|
6238
|
-
*/
|
|
6239
|
-
capitalizePhase(phase) {
|
|
6240
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
6241
|
-
}
|
|
6242
6182
|
};
|
|
6243
6183
|
|
|
6244
6184
|
// ../core/dist/system-prompt-generator.js
|
|
6245
|
-
var
|
|
6185
|
+
var logger13 = createLogger("SystemPromptGenerator");
|
|
6246
6186
|
function generateSystemPrompt(stateMachine) {
|
|
6247
|
-
|
|
6187
|
+
logger13.debug("Generating system prompt from state machine definition", {
|
|
6248
6188
|
stateMachineName: stateMachine.name,
|
|
6249
6189
|
phaseCount: Object.keys(stateMachine.states).length
|
|
6250
6190
|
});
|
|
6251
6191
|
return generateSimpleSystemPrompt(stateMachine);
|
|
6252
6192
|
}
|
|
6253
6193
|
function generateSimpleSystemPrompt(_stateMachine) {
|
|
6254
|
-
|
|
6194
|
+
logger13.debug("Generating system prompt");
|
|
6255
6195
|
const systemPrompt = `
|
|
6256
6196
|
You are an AI assistant that helps users develop software features using the workflows server.
|
|
6257
6197
|
|
|
@@ -6262,7 +6202,7 @@ Each tool call returns a JSON response with an "instructions" field. Follow thes
|
|
|
6262
6202
|
Use the development plan which you will retrieve via whats_next() to record important insights and decisions as per the structure of the plan.
|
|
6263
6203
|
|
|
6264
6204
|
Do not use your own task management tools.`;
|
|
6265
|
-
|
|
6205
|
+
logger13.info("System prompt generated successfully", {
|
|
6266
6206
|
promptLength: systemPrompt.length
|
|
6267
6207
|
});
|
|
6268
6208
|
return systemPrompt;
|
|
@@ -6277,12 +6217,13 @@ import * as path4 from "path";
|
|
|
6277
6217
|
|
|
6278
6218
|
// src/server-helpers.ts
|
|
6279
6219
|
import { homedir } from "os";
|
|
6280
|
-
var
|
|
6281
|
-
function normalizeProjectPath(projectPath) {
|
|
6220
|
+
var defaultLogger6 = createLogger("ServerHelpers");
|
|
6221
|
+
function normalizeProjectPath(projectPath, logger24) {
|
|
6222
|
+
const log = logger24 ?? defaultLogger6;
|
|
6282
6223
|
const path6 = projectPath || process.cwd();
|
|
6283
6224
|
if (path6 === "/" || path6 === "") {
|
|
6284
6225
|
const homePath = homedir();
|
|
6285
|
-
|
|
6226
|
+
log.info("Invalid project path detected, using home directory", {
|
|
6286
6227
|
originalPath: path6,
|
|
6287
6228
|
normalizedPath: homePath
|
|
6288
6229
|
});
|
|
@@ -6305,14 +6246,18 @@ function createErrorResult(error, metadata) {
|
|
|
6305
6246
|
metadata
|
|
6306
6247
|
};
|
|
6307
6248
|
}
|
|
6308
|
-
async function safeExecute(operation, errorContext) {
|
|
6249
|
+
async function safeExecute(operation, errorContext, logger24) {
|
|
6250
|
+
const log = logger24 ?? defaultLogger6;
|
|
6309
6251
|
try {
|
|
6310
6252
|
const result = await operation();
|
|
6311
6253
|
return createSuccessResult(result);
|
|
6312
6254
|
} catch (error) {
|
|
6313
6255
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
6314
6256
|
const contextualError = errorContext ? `${errorContext}: ${errorMessage}` : errorMessage;
|
|
6315
|
-
|
|
6257
|
+
const isExpectedError = errorMessage.includes("CONVERSATION_NOT_FOUND") || errorMessage.includes("Invalid workflow:");
|
|
6258
|
+
if (!isExpectedError) {
|
|
6259
|
+
log.error("Operation failed", error, { errorContext });
|
|
6260
|
+
}
|
|
6316
6261
|
return createErrorResult(contextualError);
|
|
6317
6262
|
}
|
|
6318
6263
|
}
|
|
@@ -6376,14 +6321,16 @@ function generateWorkflowDescription(workflows) {
|
|
|
6376
6321
|
description += "\u2022 **custom**: Use custom workflow from .vibe/workflows in your project\n\n";
|
|
6377
6322
|
return description;
|
|
6378
6323
|
}
|
|
6379
|
-
function logHandlerExecution(handlerName, args) {
|
|
6380
|
-
|
|
6324
|
+
function logHandlerExecution(handlerName, args, logger24) {
|
|
6325
|
+
const log = logger24 ?? defaultLogger6;
|
|
6326
|
+
log.debug(`Executing ${handlerName} handler`, {
|
|
6381
6327
|
handlerName,
|
|
6382
6328
|
argsKeys: Object.keys(args || {})
|
|
6383
6329
|
});
|
|
6384
6330
|
}
|
|
6385
|
-
function logHandlerCompletion(handlerName, result) {
|
|
6386
|
-
|
|
6331
|
+
function logHandlerCompletion(handlerName, result, logger24) {
|
|
6332
|
+
const log = logger24 ?? defaultLogger6;
|
|
6333
|
+
log.debug(`Completed ${handlerName} handler`, {
|
|
6387
6334
|
handlerName,
|
|
6388
6335
|
success: result.success,
|
|
6389
6336
|
hasData: !!result.data,
|
|
@@ -6415,12 +6362,14 @@ var notificationService = new NotificationService();
|
|
|
6415
6362
|
var PluginRegistry = class {
|
|
6416
6363
|
plugins = /* @__PURE__ */ new Map();
|
|
6417
6364
|
/**
|
|
6418
|
-
* Register a plugin
|
|
6365
|
+
* Register a plugin.
|
|
6366
|
+
*
|
|
6367
|
+
* Note: Plugins are always registered regardless of isEnabled() state.
|
|
6368
|
+
* The isEnabled() check happens at hook execution time in getEnabledPlugins().
|
|
6369
|
+
* This allows plugins to activate/deactivate dynamically based on conditions
|
|
6370
|
+
* that may change after registration (e.g., backend availability).
|
|
6419
6371
|
*/
|
|
6420
6372
|
registerPlugin(plugin) {
|
|
6421
|
-
if (!plugin.isEnabled()) {
|
|
6422
|
-
return;
|
|
6423
|
-
}
|
|
6424
6373
|
const name = plugin.getName();
|
|
6425
6374
|
if (this.plugins.has(name)) {
|
|
6426
6375
|
throw new Error(`Plugin with name '${name}' is already registered`);
|
|
@@ -6535,11 +6484,13 @@ var PluginRegistry = class {
|
|
|
6535
6484
|
|
|
6536
6485
|
// src/components/beads/beads-task-backend-client.ts
|
|
6537
6486
|
import { execSync as execSync5 } from "child_process";
|
|
6538
|
-
var
|
|
6487
|
+
var defaultLogger7 = createLogger("BeadsTaskBackendClient");
|
|
6539
6488
|
var BeadsTaskBackendClient = class {
|
|
6540
6489
|
projectPath;
|
|
6541
|
-
|
|
6490
|
+
logger;
|
|
6491
|
+
constructor(projectPath, logger24) {
|
|
6542
6492
|
this.projectPath = projectPath;
|
|
6493
|
+
this.logger = logger24 ?? defaultLogger7;
|
|
6543
6494
|
}
|
|
6544
6495
|
/**
|
|
6545
6496
|
* Execute a beads command safely
|
|
@@ -6547,7 +6498,7 @@ var BeadsTaskBackendClient = class {
|
|
|
6547
6498
|
async executeBeadsCommand(args) {
|
|
6548
6499
|
try {
|
|
6549
6500
|
const command = `bd ${args.join(" ")}`;
|
|
6550
|
-
|
|
6501
|
+
this.logger.debug("Executing beads command", {
|
|
6551
6502
|
command,
|
|
6552
6503
|
projectPath: this.projectPath
|
|
6553
6504
|
});
|
|
@@ -6559,7 +6510,7 @@ var BeadsTaskBackendClient = class {
|
|
|
6559
6510
|
return { success: true, stdout };
|
|
6560
6511
|
} catch (error) {
|
|
6561
6512
|
const execError = error;
|
|
6562
|
-
|
|
6513
|
+
this.logger.warn("Beads command failed", {
|
|
6563
6514
|
args,
|
|
6564
6515
|
error: error instanceof Error ? error.message : String(error),
|
|
6565
6516
|
stderr: execError.stderr,
|
|
@@ -6692,18 +6643,29 @@ var BeadsTaskBackendClient = class {
|
|
|
6692
6643
|
};
|
|
6693
6644
|
|
|
6694
6645
|
// src/plugin-system/beads-plugin.ts
|
|
6695
|
-
var logger21 = createLogger("BeadsPlugin");
|
|
6696
6646
|
var BeadsPlugin = class {
|
|
6697
6647
|
projectPath;
|
|
6698
6648
|
beadsStateManager;
|
|
6699
6649
|
beadsTaskBackendClient;
|
|
6700
6650
|
planManager;
|
|
6651
|
+
logger;
|
|
6652
|
+
loggerFactory;
|
|
6701
6653
|
constructor(options) {
|
|
6702
6654
|
this.projectPath = options.projectPath;
|
|
6703
|
-
this.
|
|
6704
|
-
this.
|
|
6655
|
+
this.loggerFactory = options.loggerFactory;
|
|
6656
|
+
this.logger = options.loggerFactory ? options.loggerFactory("BeadsPlugin") : createLogger("BeadsPlugin");
|
|
6657
|
+
this.beadsStateManager = new BeadsStateManager(
|
|
6658
|
+
this.projectPath,
|
|
6659
|
+
options.loggerFactory ? options.loggerFactory("BeadsStateManager") : void 0
|
|
6660
|
+
);
|
|
6661
|
+
this.beadsTaskBackendClient = new BeadsTaskBackendClient(
|
|
6662
|
+
this.projectPath,
|
|
6663
|
+
options.loggerFactory ? options.loggerFactory("BeadsTaskBackendClient") : void 0
|
|
6664
|
+
);
|
|
6705
6665
|
this.planManager = new PlanManager();
|
|
6706
|
-
|
|
6666
|
+
this.logger.debug("BeadsPlugin initialized", {
|
|
6667
|
+
projectPath: this.projectPath
|
|
6668
|
+
});
|
|
6707
6669
|
}
|
|
6708
6670
|
getName() {
|
|
6709
6671
|
return "BeadsPlugin";
|
|
@@ -6712,9 +6674,9 @@ var BeadsPlugin = class {
|
|
|
6712
6674
|
return 100;
|
|
6713
6675
|
}
|
|
6714
6676
|
isEnabled() {
|
|
6715
|
-
const taskBackendConfig = TaskBackendManager.detectTaskBackend();
|
|
6677
|
+
const taskBackendConfig = TaskBackendManager.detectTaskBackend(this.logger);
|
|
6716
6678
|
const enabled = taskBackendConfig.backend === "beads" && taskBackendConfig.isAvailable;
|
|
6717
|
-
|
|
6679
|
+
this.logger.debug("BeadsPlugin enablement check", {
|
|
6718
6680
|
backend: taskBackendConfig.backend,
|
|
6719
6681
|
isAvailable: taskBackendConfig.isAvailable,
|
|
6720
6682
|
autoDetected: !process.env["TASK_BACKEND"],
|
|
@@ -6726,7 +6688,8 @@ var BeadsPlugin = class {
|
|
|
6726
6688
|
return {
|
|
6727
6689
|
afterStartDevelopment: this.handleAfterStartDevelopment.bind(this),
|
|
6728
6690
|
beforePhaseTransition: this.handleBeforePhaseTransition.bind(this),
|
|
6729
|
-
afterPlanFileCreated: this.handleAfterPlanFileCreated.bind(this)
|
|
6691
|
+
afterPlanFileCreated: this.handleAfterPlanFileCreated.bind(this),
|
|
6692
|
+
afterInstructionsGenerated: this.handleAfterInstructionsGenerated.bind(this)
|
|
6730
6693
|
};
|
|
6731
6694
|
}
|
|
6732
6695
|
/**
|
|
@@ -6734,7 +6697,7 @@ var BeadsPlugin = class {
|
|
|
6734
6697
|
* Replaces validateBeadsTaskCompletion() method from proceed-to-phase.ts
|
|
6735
6698
|
*/
|
|
6736
6699
|
async handleBeforePhaseTransition(context, currentPhase, targetPhase) {
|
|
6737
|
-
|
|
6700
|
+
this.logger.info(
|
|
6738
6701
|
"BeadsPlugin: Validating task completion before phase transition",
|
|
6739
6702
|
{
|
|
6740
6703
|
conversationId: context.conversationId,
|
|
@@ -6749,7 +6712,7 @@ var BeadsPlugin = class {
|
|
|
6749
6712
|
targetPhase,
|
|
6750
6713
|
context.projectPath
|
|
6751
6714
|
);
|
|
6752
|
-
|
|
6715
|
+
this.logger.info(
|
|
6753
6716
|
"BeadsPlugin: Task validation passed, allowing phase transition",
|
|
6754
6717
|
{
|
|
6755
6718
|
conversationId: context.conversationId,
|
|
@@ -6758,7 +6721,7 @@ var BeadsPlugin = class {
|
|
|
6758
6721
|
}
|
|
6759
6722
|
);
|
|
6760
6723
|
} catch (error) {
|
|
6761
|
-
|
|
6724
|
+
this.logger.info(
|
|
6762
6725
|
"BeadsPlugin: Task validation failed, blocking phase transition",
|
|
6763
6726
|
{
|
|
6764
6727
|
conversationId: context.conversationId,
|
|
@@ -6776,20 +6739,25 @@ var BeadsPlugin = class {
|
|
|
6776
6739
|
* Implements graceful degradation: continues app operation even if beads operations fail
|
|
6777
6740
|
*/
|
|
6778
6741
|
async handleAfterStartDevelopment(context, args, _result) {
|
|
6779
|
-
|
|
6742
|
+
this.logger.info("BeadsPlugin: Setting up beads integration", {
|
|
6780
6743
|
conversationId: context.conversationId,
|
|
6781
6744
|
workflow: args.workflow,
|
|
6782
6745
|
projectPath: context.projectPath
|
|
6783
6746
|
});
|
|
6784
6747
|
if (!context.stateMachine) {
|
|
6785
|
-
|
|
6786
|
-
|
|
6748
|
+
this.logger.error(
|
|
6749
|
+
"BeadsPlugin: State machine not provided in plugin context"
|
|
6750
|
+
);
|
|
6751
|
+
this.logger.warn(
|
|
6787
6752
|
"BeadsPlugin: Beads integration disabled - continuing without beads"
|
|
6788
6753
|
);
|
|
6789
6754
|
return;
|
|
6790
6755
|
}
|
|
6791
6756
|
try {
|
|
6792
|
-
const beadsIntegration = new BeadsIntegration(
|
|
6757
|
+
const beadsIntegration = new BeadsIntegration(
|
|
6758
|
+
context.projectPath,
|
|
6759
|
+
this.loggerFactory ? this.loggerFactory("BeadsIntegration") : void 0
|
|
6760
|
+
);
|
|
6793
6761
|
const projectName = getPathBasename(
|
|
6794
6762
|
context.projectPath,
|
|
6795
6763
|
"Unknown Project"
|
|
@@ -6801,7 +6769,7 @@ var BeadsPlugin = class {
|
|
|
6801
6769
|
);
|
|
6802
6770
|
goalDescription = this.extractGoalFromPlan(planFileContent);
|
|
6803
6771
|
} catch (error) {
|
|
6804
|
-
|
|
6772
|
+
this.logger.warn("BeadsPlugin: Could not extract goal from plan file", {
|
|
6805
6773
|
error: error instanceof Error ? error.message : String(error),
|
|
6806
6774
|
planFilePath: context.planFilePath
|
|
6807
6775
|
});
|
|
@@ -6817,7 +6785,7 @@ var BeadsPlugin = class {
|
|
|
6817
6785
|
);
|
|
6818
6786
|
} catch (error) {
|
|
6819
6787
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6820
|
-
|
|
6788
|
+
this.logger.warn(
|
|
6821
6789
|
"BeadsPlugin: Failed to create beads project epic - continuing without beads integration",
|
|
6822
6790
|
{
|
|
6823
6791
|
error: errorMsg,
|
|
@@ -6835,7 +6803,7 @@ var BeadsPlugin = class {
|
|
|
6835
6803
|
);
|
|
6836
6804
|
} catch (error) {
|
|
6837
6805
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6838
|
-
|
|
6806
|
+
this.logger.warn(
|
|
6839
6807
|
"BeadsPlugin: Failed to create beads phase tasks - continuing without phase tracking",
|
|
6840
6808
|
{
|
|
6841
6809
|
error: errorMsg,
|
|
@@ -6848,7 +6816,7 @@ var BeadsPlugin = class {
|
|
|
6848
6816
|
await beadsIntegration.createPhaseDependencies(phaseTasks);
|
|
6849
6817
|
} catch (error) {
|
|
6850
6818
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6851
|
-
|
|
6819
|
+
this.logger.warn(
|
|
6852
6820
|
"BeadsPlugin: Failed to create phase dependencies - continuing without dependencies",
|
|
6853
6821
|
{
|
|
6854
6822
|
error: errorMsg,
|
|
@@ -6863,7 +6831,7 @@ var BeadsPlugin = class {
|
|
|
6863
6831
|
);
|
|
6864
6832
|
} catch (error) {
|
|
6865
6833
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6866
|
-
|
|
6834
|
+
this.logger.warn(
|
|
6867
6835
|
"BeadsPlugin: Failed to update plan file with beads task IDs - continuing without plan file updates",
|
|
6868
6836
|
{
|
|
6869
6837
|
error: errorMsg,
|
|
@@ -6879,7 +6847,7 @@ var BeadsPlugin = class {
|
|
|
6879
6847
|
);
|
|
6880
6848
|
} catch (error) {
|
|
6881
6849
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6882
|
-
|
|
6850
|
+
this.logger.warn(
|
|
6883
6851
|
"BeadsPlugin: Failed to create beads state - continuing without state persistence",
|
|
6884
6852
|
{
|
|
6885
6853
|
error: errorMsg,
|
|
@@ -6887,7 +6855,7 @@ var BeadsPlugin = class {
|
|
|
6887
6855
|
}
|
|
6888
6856
|
);
|
|
6889
6857
|
}
|
|
6890
|
-
|
|
6858
|
+
this.logger.info("BeadsPlugin: Beads integration setup complete", {
|
|
6891
6859
|
conversationId: context.conversationId,
|
|
6892
6860
|
epicId,
|
|
6893
6861
|
phaseCount: phaseTasks?.length || 0,
|
|
@@ -6895,7 +6863,7 @@ var BeadsPlugin = class {
|
|
|
6895
6863
|
});
|
|
6896
6864
|
} catch (error) {
|
|
6897
6865
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6898
|
-
|
|
6866
|
+
this.logger.warn(
|
|
6899
6867
|
"BeadsPlugin: Unexpected error during beads integration setup - continuing application without beads",
|
|
6900
6868
|
{
|
|
6901
6869
|
error: errorMsg,
|
|
@@ -6916,11 +6884,127 @@ var BeadsPlugin = class {
|
|
|
6916
6884
|
* This hook ensures the plan has the proper structure to receive them.
|
|
6917
6885
|
*/
|
|
6918
6886
|
async handleAfterPlanFileCreated(_context, planFilePath, content) {
|
|
6919
|
-
|
|
6887
|
+
this.logger.debug("BeadsPlugin: afterPlanFileCreated hook invoked", {
|
|
6920
6888
|
planFilePath,
|
|
6921
6889
|
contentLength: content.length
|
|
6922
6890
|
});
|
|
6923
|
-
|
|
6891
|
+
let transformed = content;
|
|
6892
|
+
transformed = transformed.replace(
|
|
6893
|
+
/### Tasks\n- \[ \] \*Tasks will be added as they are identified\*\n\n### Completed\n- \[x\] Created development plan file/g,
|
|
6894
|
+
"<!-- beads-phase-id: TBD -->\n### Tasks\n\n*Tasks managed via `bd` CLI*"
|
|
6895
|
+
);
|
|
6896
|
+
transformed = transformed.replace(
|
|
6897
|
+
/### Tasks\n- \[ \] \*To be added when this phase becomes active\*\n\n### Completed\n\*None yet\*/g,
|
|
6898
|
+
"<!-- beads-phase-id: TBD -->\n### Tasks\n\n*Tasks managed via `bd` CLI*"
|
|
6899
|
+
);
|
|
6900
|
+
transformed = transformed.replace(
|
|
6901
|
+
/\*This plan is maintained by the LLM\. Tool responses provide guidance on which section to focus on and what tasks to work on\.\*/,
|
|
6902
|
+
"*This plan is maintained by the LLM and uses beads CLI for task management. Tool responses provide guidance on which bd commands to use for task management.*"
|
|
6903
|
+
);
|
|
6904
|
+
this.logger.debug("BeadsPlugin: Plan file transformed for beads", {
|
|
6905
|
+
planFilePath,
|
|
6906
|
+
originalLength: content.length,
|
|
6907
|
+
transformedLength: transformed.length,
|
|
6908
|
+
wasModified: content !== transformed
|
|
6909
|
+
});
|
|
6910
|
+
return transformed;
|
|
6911
|
+
}
|
|
6912
|
+
/**
|
|
6913
|
+
* Handle afterInstructionsGenerated hook
|
|
6914
|
+
* Enriches instructions with beads-specific task management guidance
|
|
6915
|
+
*/
|
|
6916
|
+
async handleAfterInstructionsGenerated(context, instructions) {
|
|
6917
|
+
this.logger.debug("BeadsPlugin: afterInstructionsGenerated hook invoked", {
|
|
6918
|
+
phase: instructions.phase,
|
|
6919
|
+
instructionSource: instructions.instructionSource,
|
|
6920
|
+
planFilePath: instructions.planFilePath
|
|
6921
|
+
});
|
|
6922
|
+
const beadsGuidance = await this.generateBeadsGuidance(
|
|
6923
|
+
context,
|
|
6924
|
+
instructions
|
|
6925
|
+
);
|
|
6926
|
+
let enhanced = instructions.instructions;
|
|
6927
|
+
enhanced += `
|
|
6928
|
+
|
|
6929
|
+
Log decisions in plan file. Use ONLY \`bd\` CLI for tasks (not your own todo tools).${beadsGuidance}`;
|
|
6930
|
+
if (context.planFileExists === false) {
|
|
6931
|
+
enhanced += "\n\n**Note**: Plan file will be created when you first update it.";
|
|
6932
|
+
}
|
|
6933
|
+
enhanced += "\n\nCall `whats_next()` after user messages.";
|
|
6934
|
+
this.logger.debug(
|
|
6935
|
+
"BeadsPlugin: Instructions enriched with beads guidance",
|
|
6936
|
+
{
|
|
6937
|
+
originalLength: instructions.instructions.length,
|
|
6938
|
+
enrichedLength: enhanced.length
|
|
6939
|
+
}
|
|
6940
|
+
);
|
|
6941
|
+
return {
|
|
6942
|
+
...instructions,
|
|
6943
|
+
instructions: enhanced
|
|
6944
|
+
};
|
|
6945
|
+
}
|
|
6946
|
+
/**
|
|
6947
|
+
* Generate beads-specific task management guidance
|
|
6948
|
+
*/
|
|
6949
|
+
async generateBeadsGuidance(_context, instructions) {
|
|
6950
|
+
if (instructions.instructionSource === "whats_next" || instructions.instructionSource === "start_development") {
|
|
6951
|
+
const phaseTaskId = await this.extractPhaseTaskIdFromPlanFile(
|
|
6952
|
+
instructions.planFilePath,
|
|
6953
|
+
instructions.phase
|
|
6954
|
+
);
|
|
6955
|
+
if (!phaseTaskId) {
|
|
6956
|
+
return `
|
|
6957
|
+
|
|
6958
|
+
**Task Management (bd CLI):**
|
|
6959
|
+
Create tasks as sub-tasks of phase task: \`bd create 'title' --parent <phase-task-id>\`
|
|
6960
|
+
List open tasks: \`bd list --parent <phase-task-id> --status open\`
|
|
6961
|
+
Complete tasks: \`bd close <id>\``;
|
|
6962
|
+
}
|
|
6963
|
+
return `
|
|
6964
|
+
|
|
6965
|
+
**Task Management (bd CLI) - Phase: ${phaseTaskId}**
|
|
6966
|
+
Create tasks as sub-tasks: \`bd create 'title' --parent ${phaseTaskId}\`
|
|
6967
|
+
List open tasks: \`bd list --parent ${phaseTaskId} --status open\`
|
|
6968
|
+
Complete tasks: \`bd close <id>\``;
|
|
6969
|
+
}
|
|
6970
|
+
return "";
|
|
6971
|
+
}
|
|
6972
|
+
/**
|
|
6973
|
+
* Extract phase task ID from plan file
|
|
6974
|
+
*/
|
|
6975
|
+
async extractPhaseTaskIdFromPlanFile(planFilePath, phase) {
|
|
6976
|
+
try {
|
|
6977
|
+
const { readFile: readFile5 } = await import("fs/promises");
|
|
6978
|
+
const content = await readFile5(planFilePath, "utf-8");
|
|
6979
|
+
const phaseName = this.capitalizePhase(phase);
|
|
6980
|
+
const phaseHeader = `## ${phaseName}`;
|
|
6981
|
+
const lines = content.split("\n");
|
|
6982
|
+
let foundPhaseHeader = false;
|
|
6983
|
+
for (const line of lines) {
|
|
6984
|
+
if (line.trim() === phaseHeader) {
|
|
6985
|
+
foundPhaseHeader = true;
|
|
6986
|
+
continue;
|
|
6987
|
+
}
|
|
6988
|
+
if (foundPhaseHeader && line.includes("beads-phase-id:")) {
|
|
6989
|
+
const match = line.match(/beads-phase-id:\s*([\w\d.-]+)/);
|
|
6990
|
+
if (match && match[1] && match[1] !== "TBD") {
|
|
6991
|
+
return match[1];
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6994
|
+
if (foundPhaseHeader && line.startsWith("##") && line !== phaseHeader) {
|
|
6995
|
+
break;
|
|
6996
|
+
}
|
|
6997
|
+
}
|
|
6998
|
+
return null;
|
|
6999
|
+
} catch (_error) {
|
|
7000
|
+
return null;
|
|
7001
|
+
}
|
|
7002
|
+
}
|
|
7003
|
+
/**
|
|
7004
|
+
* Capitalize phase name for display
|
|
7005
|
+
*/
|
|
7006
|
+
capitalizePhase(phase) {
|
|
7007
|
+
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
6924
7008
|
}
|
|
6925
7009
|
/**
|
|
6926
7010
|
* Validate beads task completion before phase transition
|
|
@@ -6933,14 +7017,14 @@ var BeadsPlugin = class {
|
|
|
6933
7017
|
isAvailable = await this.beadsTaskBackendClient.isAvailable();
|
|
6934
7018
|
} catch (error) {
|
|
6935
7019
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6936
|
-
|
|
7020
|
+
this.logger.warn("BeadsPlugin: Failed to check beads availability", {
|
|
6937
7021
|
error: errorMsg,
|
|
6938
7022
|
conversationId
|
|
6939
7023
|
});
|
|
6940
7024
|
return;
|
|
6941
7025
|
}
|
|
6942
7026
|
if (!isAvailable) {
|
|
6943
|
-
|
|
7027
|
+
this.logger.debug(
|
|
6944
7028
|
"BeadsPlugin: Skipping beads task validation - beads CLI not available",
|
|
6945
7029
|
{
|
|
6946
7030
|
conversationId,
|
|
@@ -6958,7 +7042,7 @@ var BeadsPlugin = class {
|
|
|
6958
7042
|
);
|
|
6959
7043
|
} catch (error) {
|
|
6960
7044
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6961
|
-
|
|
7045
|
+
this.logger.warn("BeadsPlugin: Failed to get beads phase task ID", {
|
|
6962
7046
|
error: errorMsg,
|
|
6963
7047
|
conversationId,
|
|
6964
7048
|
currentPhase
|
|
@@ -6966,7 +7050,7 @@ var BeadsPlugin = class {
|
|
|
6966
7050
|
return;
|
|
6967
7051
|
}
|
|
6968
7052
|
if (!currentPhaseTaskId) {
|
|
6969
|
-
|
|
7053
|
+
this.logger.debug(
|
|
6970
7054
|
"BeadsPlugin: No beads phase task ID found for current phase",
|
|
6971
7055
|
{
|
|
6972
7056
|
conversationId,
|
|
@@ -6977,7 +7061,7 @@ var BeadsPlugin = class {
|
|
|
6977
7061
|
);
|
|
6978
7062
|
return;
|
|
6979
7063
|
}
|
|
6980
|
-
|
|
7064
|
+
this.logger.debug(
|
|
6981
7065
|
"BeadsPlugin: Checking for incomplete beads tasks using task backend client",
|
|
6982
7066
|
{
|
|
6983
7067
|
conversationId,
|
|
@@ -6992,7 +7076,7 @@ var BeadsPlugin = class {
|
|
|
6992
7076
|
);
|
|
6993
7077
|
} catch (error) {
|
|
6994
7078
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
6995
|
-
|
|
7079
|
+
this.logger.warn(
|
|
6996
7080
|
"BeadsPlugin: Failed to validate tasks with beads backend",
|
|
6997
7081
|
{
|
|
6998
7082
|
error: errorMsg,
|
|
@@ -7004,18 +7088,9 @@ var BeadsPlugin = class {
|
|
|
7004
7088
|
}
|
|
7005
7089
|
if (!validationResult.valid) {
|
|
7006
7090
|
const incompleteTasks = validationResult.openTasks || [];
|
|
7007
|
-
const
|
|
7008
|
-
const errorMessage =
|
|
7009
|
-
|
|
7010
|
-
${taskDetails}
|
|
7011
|
-
|
|
7012
|
-
To proceed, check the in-progress-tasks using:
|
|
7013
|
-
|
|
7014
|
-
bd list --parent ${currentPhaseTaskId} --status open
|
|
7015
|
-
|
|
7016
|
-
You can also defer tasks if they're no longer needed:
|
|
7017
|
-
bd defer <task-id> --until tomorrow`;
|
|
7018
|
-
logger21.info(
|
|
7091
|
+
const taskIds = incompleteTasks.map((t) => t.id).join(", ");
|
|
7092
|
+
const errorMessage = `${incompleteTasks.length} incomplete task(s) in ${currentPhase}: ${taskIds}. Complete or defer (\`bd defer <id>\`) before proceeding.`;
|
|
7093
|
+
this.logger.info(
|
|
7019
7094
|
"BeadsPlugin: Blocking phase transition due to incomplete beads tasks",
|
|
7020
7095
|
{
|
|
7021
7096
|
conversationId,
|
|
@@ -7028,7 +7103,7 @@ You can also defer tasks if they're no longer needed:
|
|
|
7028
7103
|
);
|
|
7029
7104
|
throw new Error(errorMessage);
|
|
7030
7105
|
}
|
|
7031
|
-
|
|
7106
|
+
this.logger.info(
|
|
7032
7107
|
"BeadsPlugin: All beads tasks completed in current phase, allowing transition",
|
|
7033
7108
|
{
|
|
7034
7109
|
conversationId,
|
|
@@ -7042,7 +7117,7 @@ You can also defer tasks if they're no longer needed:
|
|
|
7042
7117
|
throw error;
|
|
7043
7118
|
}
|
|
7044
7119
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
7045
|
-
|
|
7120
|
+
this.logger.warn(
|
|
7046
7121
|
"BeadsPlugin: Beads task validation failed, allowing transition to proceed",
|
|
7047
7122
|
{
|
|
7048
7123
|
error: errorMessage,
|
|
@@ -7095,13 +7170,13 @@ You can also defer tasks if they're no longer needed:
|
|
|
7095
7170
|
*/
|
|
7096
7171
|
async updatePlanFileWithPhaseTaskIds(planFilePath, phaseTasks) {
|
|
7097
7172
|
try {
|
|
7098
|
-
const { readFile:
|
|
7173
|
+
const { readFile: readFile5, writeFile: writeFile5 } = await import("fs/promises");
|
|
7099
7174
|
let content;
|
|
7100
7175
|
try {
|
|
7101
|
-
content = await
|
|
7176
|
+
content = await readFile5(planFilePath, "utf-8");
|
|
7102
7177
|
} catch (error) {
|
|
7103
7178
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
7104
|
-
|
|
7179
|
+
this.logger.warn("BeadsPlugin: Failed to read plan file for update", {
|
|
7105
7180
|
error: errorMsg,
|
|
7106
7181
|
planFilePath
|
|
7107
7182
|
});
|
|
@@ -7121,7 +7196,7 @@ You can also defer tasks if they're no longer needed:
|
|
|
7121
7196
|
}
|
|
7122
7197
|
const remainingTBDs = content.match(/<!-- beads-phase-id: TBD -->/g);
|
|
7123
7198
|
if (remainingTBDs && remainingTBDs.length > 0) {
|
|
7124
|
-
|
|
7199
|
+
this.logger.warn(
|
|
7125
7200
|
"BeadsPlugin: Failed to replace all TBD placeholders in plan file",
|
|
7126
7201
|
{
|
|
7127
7202
|
planFilePath,
|
|
@@ -7131,16 +7206,16 @@ You can also defer tasks if they're no longer needed:
|
|
|
7131
7206
|
);
|
|
7132
7207
|
}
|
|
7133
7208
|
try {
|
|
7134
|
-
await
|
|
7209
|
+
await writeFile5(planFilePath, content, "utf-8");
|
|
7135
7210
|
} catch (error) {
|
|
7136
7211
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
7137
|
-
|
|
7212
|
+
this.logger.warn("BeadsPlugin: Failed to write updated plan file", {
|
|
7138
7213
|
error: errorMsg,
|
|
7139
7214
|
planFilePath
|
|
7140
7215
|
});
|
|
7141
7216
|
return;
|
|
7142
7217
|
}
|
|
7143
|
-
|
|
7218
|
+
this.logger.info(
|
|
7144
7219
|
"BeadsPlugin: Successfully updated plan file with beads phase task IDs",
|
|
7145
7220
|
{
|
|
7146
7221
|
planFilePath,
|
|
@@ -7152,7 +7227,7 @@ You can also defer tasks if they're no longer needed:
|
|
|
7152
7227
|
);
|
|
7153
7228
|
} catch (error) {
|
|
7154
7229
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
7155
|
-
|
|
7230
|
+
this.logger.warn(
|
|
7156
7231
|
"BeadsPlugin: Unexpected error while updating plan file with phase task IDs",
|
|
7157
7232
|
{
|
|
7158
7233
|
error: errorMsg,
|
|
@@ -7164,13 +7239,13 @@ You can also defer tasks if they're no longer needed:
|
|
|
7164
7239
|
};
|
|
7165
7240
|
|
|
7166
7241
|
// src/plugin-system/commit-plugin.ts
|
|
7167
|
-
var
|
|
7242
|
+
var logger14 = createLogger("CommitPlugin");
|
|
7168
7243
|
var CommitPlugin = class {
|
|
7169
7244
|
projectPath;
|
|
7170
7245
|
initialCommitHash;
|
|
7171
7246
|
constructor(options) {
|
|
7172
7247
|
this.projectPath = options.projectPath;
|
|
7173
|
-
|
|
7248
|
+
logger14.debug("CommitPlugin initialized", { projectPath: this.projectPath });
|
|
7174
7249
|
}
|
|
7175
7250
|
getName() {
|
|
7176
7251
|
return "CommitPlugin";
|
|
@@ -7181,7 +7256,7 @@ var CommitPlugin = class {
|
|
|
7181
7256
|
isEnabled() {
|
|
7182
7257
|
const behavior = process.env.COMMIT_BEHAVIOR;
|
|
7183
7258
|
const enabled = behavior && ["step", "phase", "end", "none"].includes(behavior);
|
|
7184
|
-
|
|
7259
|
+
logger14.debug("CommitPlugin enablement check", {
|
|
7185
7260
|
COMMIT_BEHAVIOR: behavior,
|
|
7186
7261
|
enabled: !!enabled
|
|
7187
7262
|
});
|
|
@@ -7199,7 +7274,7 @@ var CommitPlugin = class {
|
|
|
7199
7274
|
* Store initial commit hash for potential squashing later
|
|
7200
7275
|
*/
|
|
7201
7276
|
async handleAfterStartDevelopment(context, _args, _result) {
|
|
7202
|
-
|
|
7277
|
+
logger14.info("CommitPlugin: Setting up commit behavior", {
|
|
7203
7278
|
conversationId: context.conversationId,
|
|
7204
7279
|
behavior: process.env.COMMIT_BEHAVIOR,
|
|
7205
7280
|
projectPath: context.projectPath
|
|
@@ -7207,13 +7282,13 @@ var CommitPlugin = class {
|
|
|
7207
7282
|
try {
|
|
7208
7283
|
if (GitManager.isGitRepository(context.projectPath)) {
|
|
7209
7284
|
this.initialCommitHash = GitManager.getCurrentCommitHash(context.projectPath) || void 0;
|
|
7210
|
-
|
|
7285
|
+
logger14.debug("CommitPlugin: Stored initial commit hash", {
|
|
7211
7286
|
conversationId: context.conversationId,
|
|
7212
7287
|
initialCommitHash: this.initialCommitHash
|
|
7213
7288
|
});
|
|
7214
7289
|
}
|
|
7215
7290
|
} catch (error) {
|
|
7216
|
-
|
|
7291
|
+
logger14.warn("CommitPlugin: Failed to get initial commit hash", {
|
|
7217
7292
|
error: error instanceof Error ? error.message : String(error),
|
|
7218
7293
|
conversationId: context.conversationId
|
|
7219
7294
|
});
|
|
@@ -7228,7 +7303,7 @@ var CommitPlugin = class {
|
|
|
7228
7303
|
if (behavior !== "phase" && behavior !== "step") {
|
|
7229
7304
|
return;
|
|
7230
7305
|
}
|
|
7231
|
-
|
|
7306
|
+
logger14.info("CommitPlugin: Creating WIP commit before phase transition", {
|
|
7232
7307
|
conversationId: context.conversationId,
|
|
7233
7308
|
currentPhase,
|
|
7234
7309
|
targetPhase,
|
|
@@ -7236,28 +7311,28 @@ var CommitPlugin = class {
|
|
|
7236
7311
|
});
|
|
7237
7312
|
try {
|
|
7238
7313
|
if (!GitManager.isGitRepository(context.projectPath)) {
|
|
7239
|
-
|
|
7314
|
+
logger14.debug("CommitPlugin: Not a git repository, skipping commit");
|
|
7240
7315
|
return;
|
|
7241
7316
|
}
|
|
7242
7317
|
if (!GitManager.hasUncommittedChanges(context.projectPath)) {
|
|
7243
|
-
|
|
7318
|
+
logger14.debug("CommitPlugin: No uncommitted changes, skipping commit");
|
|
7244
7319
|
return;
|
|
7245
7320
|
}
|
|
7246
7321
|
const message = `WIP: transition to ${targetPhase}`;
|
|
7247
7322
|
const success = GitManager.createCommit(message, context.projectPath);
|
|
7248
7323
|
if (success) {
|
|
7249
|
-
|
|
7324
|
+
logger14.info("CommitPlugin: Created WIP commit successfully", {
|
|
7250
7325
|
conversationId: context.conversationId,
|
|
7251
7326
|
message
|
|
7252
7327
|
});
|
|
7253
7328
|
} else {
|
|
7254
|
-
|
|
7329
|
+
logger14.warn("CommitPlugin: Failed to create WIP commit", {
|
|
7255
7330
|
conversationId: context.conversationId,
|
|
7256
7331
|
message
|
|
7257
7332
|
});
|
|
7258
7333
|
}
|
|
7259
7334
|
} catch (error) {
|
|
7260
|
-
|
|
7335
|
+
logger14.warn("CommitPlugin: Error during phase transition commit", {
|
|
7261
7336
|
error: error instanceof Error ? error.message : String(error),
|
|
7262
7337
|
conversationId: context.conversationId
|
|
7263
7338
|
});
|
|
@@ -7272,7 +7347,7 @@ var CommitPlugin = class {
|
|
|
7272
7347
|
if (!behavior || behavior === "none") {
|
|
7273
7348
|
return content;
|
|
7274
7349
|
}
|
|
7275
|
-
|
|
7350
|
+
logger14.debug("CommitPlugin: Adding final commit task to plan file", {
|
|
7276
7351
|
conversationId: context.conversationId,
|
|
7277
7352
|
behavior,
|
|
7278
7353
|
planFilePath
|
|
@@ -7296,7 +7371,7 @@ var CommitPlugin = class {
|
|
|
7296
7371
|
}
|
|
7297
7372
|
}
|
|
7298
7373
|
if (finalPhaseIndex === -1) {
|
|
7299
|
-
|
|
7374
|
+
logger14.warn(
|
|
7300
7375
|
"CommitPlugin: Could not find final phase to add commit task"
|
|
7301
7376
|
);
|
|
7302
7377
|
return content;
|
|
@@ -7322,14 +7397,14 @@ var CommitPlugin = class {
|
|
|
7322
7397
|
lines.splice(finalPhaseIndex + 1, 0, "", "### Tasks", commitTask);
|
|
7323
7398
|
}
|
|
7324
7399
|
const updatedContent = lines.join("\n");
|
|
7325
|
-
|
|
7400
|
+
logger14.info("CommitPlugin: Added final commit task to plan file", {
|
|
7326
7401
|
conversationId: context.conversationId,
|
|
7327
7402
|
behavior,
|
|
7328
7403
|
commitTask
|
|
7329
7404
|
});
|
|
7330
7405
|
return updatedContent;
|
|
7331
7406
|
} catch (error) {
|
|
7332
|
-
|
|
7407
|
+
logger14.warn("CommitPlugin: Failed to add commit task to plan file", {
|
|
7333
7408
|
error: error instanceof Error ? error.message : String(error),
|
|
7334
7409
|
conversationId: context.conversationId
|
|
7335
7410
|
});
|
|
@@ -7338,416 +7413,16 @@ var CommitPlugin = class {
|
|
|
7338
7413
|
}
|
|
7339
7414
|
};
|
|
7340
7415
|
|
|
7341
|
-
// src/components/beads/beads-plan-manager.ts
|
|
7342
|
-
import { writeFile as writeFile4, readFile as readFile4, access as access6 } from "fs/promises";
|
|
7343
|
-
import { dirname as dirname6 } from "path";
|
|
7344
|
-
import { mkdir as mkdir4 } from "fs/promises";
|
|
7345
|
-
var logger23 = createLogger("BeadsPlanManager");
|
|
7346
|
-
var BeadsPlanManager = class {
|
|
7347
|
-
stateMachine = null;
|
|
7348
|
-
/**
|
|
7349
|
-
* Set the state machine definition for dynamic plan generation
|
|
7350
|
-
*/
|
|
7351
|
-
setStateMachine(stateMachine) {
|
|
7352
|
-
this.stateMachine = stateMachine;
|
|
7353
|
-
logger23.debug("State machine set for beads plan manager", {
|
|
7354
|
-
name: stateMachine.name,
|
|
7355
|
-
phases: Object.keys(stateMachine.states)
|
|
7356
|
-
});
|
|
7357
|
-
}
|
|
7358
|
-
/**
|
|
7359
|
-
* Set the task backend configuration
|
|
7360
|
-
*/
|
|
7361
|
-
setTaskBackend(taskBackend) {
|
|
7362
|
-
logger23.debug("Task backend set for beads plan manager", {
|
|
7363
|
-
backend: taskBackend.backend,
|
|
7364
|
-
available: taskBackend.isAvailable
|
|
7365
|
-
});
|
|
7366
|
-
}
|
|
7367
|
-
/**
|
|
7368
|
-
* Get plan file information
|
|
7369
|
-
*/
|
|
7370
|
-
async getPlanFileInfo(planFilePath) {
|
|
7371
|
-
try {
|
|
7372
|
-
await access6(planFilePath);
|
|
7373
|
-
const content = await readFile4(planFilePath, "utf-8");
|
|
7374
|
-
return {
|
|
7375
|
-
path: planFilePath,
|
|
7376
|
-
exists: true,
|
|
7377
|
-
content
|
|
7378
|
-
};
|
|
7379
|
-
} catch (_error) {
|
|
7380
|
-
return {
|
|
7381
|
-
path: planFilePath,
|
|
7382
|
-
exists: false
|
|
7383
|
-
};
|
|
7384
|
-
}
|
|
7385
|
-
}
|
|
7386
|
-
/**
|
|
7387
|
-
* Create initial plan file if it doesn't exist
|
|
7388
|
-
*/
|
|
7389
|
-
async ensurePlanFile(planFilePath, projectPath, gitBranch) {
|
|
7390
|
-
logger23.debug("Ensuring beads plan file exists", {
|
|
7391
|
-
planFilePath,
|
|
7392
|
-
projectPath,
|
|
7393
|
-
gitBranch
|
|
7394
|
-
});
|
|
7395
|
-
const planInfo = await this.getPlanFileInfo(planFilePath);
|
|
7396
|
-
if (!planInfo.exists) {
|
|
7397
|
-
logger23.info("Plan file not found, creating beads-optimized plan", {
|
|
7398
|
-
planFilePath
|
|
7399
|
-
});
|
|
7400
|
-
await this.createInitialBeadsPlanFile(
|
|
7401
|
-
planFilePath,
|
|
7402
|
-
projectPath,
|
|
7403
|
-
gitBranch
|
|
7404
|
-
);
|
|
7405
|
-
logger23.info("Beads plan file created successfully", { planFilePath });
|
|
7406
|
-
} else {
|
|
7407
|
-
logger23.debug("Plan file already exists", { planFilePath });
|
|
7408
|
-
}
|
|
7409
|
-
}
|
|
7410
|
-
/**
|
|
7411
|
-
* Create initial plan file optimized for beads workflow
|
|
7412
|
-
*/
|
|
7413
|
-
async createInitialBeadsPlanFile(planFilePath, projectPath, gitBranch) {
|
|
7414
|
-
logger23.debug("Creating beads-optimized plan file", { planFilePath });
|
|
7415
|
-
try {
|
|
7416
|
-
await mkdir4(dirname6(planFilePath), { recursive: true });
|
|
7417
|
-
logger23.debug("Plan file directory ensured", {
|
|
7418
|
-
directory: dirname6(planFilePath)
|
|
7419
|
-
});
|
|
7420
|
-
const projectName = getPathBasename(projectPath, "Unknown Project");
|
|
7421
|
-
const branchInfo = gitBranch !== "no-git" ? ` (${gitBranch} branch)` : "";
|
|
7422
|
-
const initialContent = this.generateBeadsInitialPlanContent(
|
|
7423
|
-
projectName,
|
|
7424
|
-
branchInfo
|
|
7425
|
-
);
|
|
7426
|
-
await writeFile4(planFilePath, initialContent, "utf-8");
|
|
7427
|
-
logger23.info("Beads plan file written successfully", {
|
|
7428
|
-
planFilePath,
|
|
7429
|
-
contentLength: initialContent.length,
|
|
7430
|
-
projectName
|
|
7431
|
-
});
|
|
7432
|
-
} catch (error) {
|
|
7433
|
-
logger23.error("Failed to create beads plan file", error, {
|
|
7434
|
-
planFilePath
|
|
7435
|
-
});
|
|
7436
|
-
throw error;
|
|
7437
|
-
}
|
|
7438
|
-
}
|
|
7439
|
-
/**
|
|
7440
|
-
* Generate initial plan file content optimized for beads workflow
|
|
7441
|
-
*/
|
|
7442
|
-
generateBeadsInitialPlanContent(projectName, branchInfo) {
|
|
7443
|
-
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
7444
|
-
if (!this.stateMachine) {
|
|
7445
|
-
throw new Error(
|
|
7446
|
-
"State machine not set. This should not happen as state machine is always loaded."
|
|
7447
|
-
);
|
|
7448
|
-
}
|
|
7449
|
-
const phases = Object.keys(this.stateMachine.states);
|
|
7450
|
-
const initialPhase = this.stateMachine.initial_state;
|
|
7451
|
-
const documentationUrl = this.generateWorkflowDocumentationUrl(
|
|
7452
|
-
this.stateMachine.name
|
|
7453
|
-
);
|
|
7454
|
-
let content = `# Development Plan: ${projectName}${branchInfo}
|
|
7455
|
-
|
|
7456
|
-
*Generated on ${timestamp2} by Vibe Feature MCP*
|
|
7457
|
-
*Workflow: ${documentationUrl ? "[" + this.stateMachine.name + "](" + documentationUrl + ")" : this.stateMachine.name}*
|
|
7458
|
-
|
|
7459
|
-
## Goal
|
|
7460
|
-
*Define what you're building or fixing - this will be updated as requirements are gathered*
|
|
7461
|
-
|
|
7462
|
-
## ${this.capitalizePhase(initialPhase)}
|
|
7463
|
-
<!-- beads-phase-id: TBD -->
|
|
7464
|
-
### Tasks
|
|
7465
|
-
|
|
7466
|
-
*Tasks managed via \`bd\` CLI*
|
|
7467
|
-
|
|
7468
|
-
`;
|
|
7469
|
-
for (const phase of phases) {
|
|
7470
|
-
if (phase !== initialPhase) {
|
|
7471
|
-
content += `## ${this.capitalizePhase(phase)}
|
|
7472
|
-
<!-- beads-phase-id: TBD -->
|
|
7473
|
-
### Tasks
|
|
7474
|
-
|
|
7475
|
-
*Tasks managed via \`bd\` CLI*
|
|
7476
|
-
|
|
7477
|
-
`;
|
|
7478
|
-
}
|
|
7479
|
-
}
|
|
7480
|
-
content += `## Key Decisions
|
|
7481
|
-
*Important decisions will be documented here as they are made*
|
|
7482
|
-
|
|
7483
|
-
## Notes
|
|
7484
|
-
*Additional context and observations*
|
|
7485
|
-
|
|
7486
|
-
---
|
|
7487
|
-
*This plan is maintained by the LLM and uses beads CLI for task management. Tool responses provide guidance on which bd commands to use for task management.*
|
|
7488
|
-
`;
|
|
7489
|
-
return content;
|
|
7490
|
-
}
|
|
7491
|
-
/**
|
|
7492
|
-
* Update plan file with new content
|
|
7493
|
-
*/
|
|
7494
|
-
async updatePlanFile(planFilePath, content) {
|
|
7495
|
-
await mkdir4(dirname6(planFilePath), { recursive: true });
|
|
7496
|
-
await writeFile4(planFilePath, content, "utf-8");
|
|
7497
|
-
}
|
|
7498
|
-
/**
|
|
7499
|
-
* Get plan file content for LLM context
|
|
7500
|
-
*/
|
|
7501
|
-
async getPlanFileContent(planFilePath) {
|
|
7502
|
-
const planInfo = await this.getPlanFileInfo(planFilePath);
|
|
7503
|
-
if (!planInfo.exists) {
|
|
7504
|
-
return "Plan file does not exist yet. It will be created when the LLM updates it.";
|
|
7505
|
-
}
|
|
7506
|
-
return planInfo.content || "";
|
|
7507
|
-
}
|
|
7508
|
-
/**
|
|
7509
|
-
* Generate phase-specific plan file guidance optimized for beads
|
|
7510
|
-
*/
|
|
7511
|
-
generatePlanFileGuidance(phase) {
|
|
7512
|
-
if (!this.stateMachine) {
|
|
7513
|
-
throw new Error(
|
|
7514
|
-
"State machine not set. This should not happen as state machine is always loaded."
|
|
7515
|
-
);
|
|
7516
|
-
}
|
|
7517
|
-
const phaseDefinition = this.stateMachine.states[phase];
|
|
7518
|
-
if (!phaseDefinition) {
|
|
7519
|
-
logger23.warn("Unknown phase for beads plan file guidance", { phase });
|
|
7520
|
-
return `Track key decisions and take notes in the plan file. Use bd CLI for all task management.`;
|
|
7521
|
-
}
|
|
7522
|
-
return `Track key decisions and take notes in the plan file. Use bd CLI exclusively for task management - never use checkboxes. Document important decisions in the Key Decisions section.`;
|
|
7523
|
-
}
|
|
7524
|
-
/**
|
|
7525
|
-
* Delete plan file
|
|
7526
|
-
*/
|
|
7527
|
-
async deletePlanFile(planFilePath) {
|
|
7528
|
-
logger23.debug("Deleting beads plan file", { planFilePath });
|
|
7529
|
-
try {
|
|
7530
|
-
await access6(planFilePath);
|
|
7531
|
-
const { unlink: unlink2 } = await import("fs/promises");
|
|
7532
|
-
await unlink2(planFilePath);
|
|
7533
|
-
logger23.info("Beads plan file deleted successfully", { planFilePath });
|
|
7534
|
-
return true;
|
|
7535
|
-
} catch (error) {
|
|
7536
|
-
if (error.code === "ENOENT") {
|
|
7537
|
-
logger23.debug("Beads plan file does not exist, nothing to delete", {
|
|
7538
|
-
planFilePath
|
|
7539
|
-
});
|
|
7540
|
-
return true;
|
|
7541
|
-
}
|
|
7542
|
-
logger23.error("Failed to delete beads plan file", error, {
|
|
7543
|
-
planFilePath
|
|
7544
|
-
});
|
|
7545
|
-
throw error;
|
|
7546
|
-
}
|
|
7547
|
-
}
|
|
7548
|
-
/**
|
|
7549
|
-
* Ensure plan file is deleted (verify deletion)
|
|
7550
|
-
*/
|
|
7551
|
-
async ensurePlanFileDeleted(planFilePath) {
|
|
7552
|
-
logger23.debug("Ensuring beads plan file is deleted", { planFilePath });
|
|
7553
|
-
try {
|
|
7554
|
-
await access6(planFilePath);
|
|
7555
|
-
logger23.warn("Beads plan file still exists after deletion attempt", {
|
|
7556
|
-
planFilePath
|
|
7557
|
-
});
|
|
7558
|
-
return false;
|
|
7559
|
-
} catch (error) {
|
|
7560
|
-
if (error.code === "ENOENT") {
|
|
7561
|
-
logger23.debug("Beads plan file successfully deleted (does not exist)", {
|
|
7562
|
-
planFilePath
|
|
7563
|
-
});
|
|
7564
|
-
return true;
|
|
7565
|
-
}
|
|
7566
|
-
logger23.error("Error checking beads plan file deletion", error, {
|
|
7567
|
-
planFilePath
|
|
7568
|
-
});
|
|
7569
|
-
throw error;
|
|
7570
|
-
}
|
|
7571
|
-
}
|
|
7572
|
-
/**
|
|
7573
|
-
* Capitalize phase name for display
|
|
7574
|
-
*/
|
|
7575
|
-
capitalizePhase(phase) {
|
|
7576
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
7577
|
-
}
|
|
7578
|
-
/**
|
|
7579
|
-
* Generate workflow documentation URL for predefined workflows
|
|
7580
|
-
*/
|
|
7581
|
-
generateWorkflowDocumentationUrl(workflowName) {
|
|
7582
|
-
if (workflowName === "custom") {
|
|
7583
|
-
return void 0;
|
|
7584
|
-
}
|
|
7585
|
-
return `https://mrsimpson.github.io/responsible-vibe-mcp/workflows/${workflowName}`;
|
|
7586
|
-
}
|
|
7587
|
-
};
|
|
7588
|
-
|
|
7589
|
-
// src/components/beads/beads-instruction-generator.ts
|
|
7590
|
-
var BeadsInstructionGenerator = class {
|
|
7591
|
-
projectDocsManager;
|
|
7592
|
-
constructor() {
|
|
7593
|
-
this.projectDocsManager = new ProjectDocsManager();
|
|
7594
|
-
}
|
|
7595
|
-
/**
|
|
7596
|
-
* Set the state machine definition (interface requirement)
|
|
7597
|
-
*/
|
|
7598
|
-
setStateMachine(_stateMachine) {
|
|
7599
|
-
}
|
|
7600
|
-
/**
|
|
7601
|
-
* Generate comprehensive instructions optimized for beads workflow
|
|
7602
|
-
*/
|
|
7603
|
-
async generateInstructions(baseInstructions, context) {
|
|
7604
|
-
const substitutedInstructions = this.applyVariableSubstitution(
|
|
7605
|
-
baseInstructions,
|
|
7606
|
-
context.conversationContext.projectPath,
|
|
7607
|
-
context.conversationContext.gitBranch
|
|
7608
|
-
);
|
|
7609
|
-
const enhancedInstructions = await this.enhanceBeadsInstructions(
|
|
7610
|
-
substitutedInstructions,
|
|
7611
|
-
context
|
|
7612
|
-
);
|
|
7613
|
-
return {
|
|
7614
|
-
instructions: enhancedInstructions,
|
|
7615
|
-
planFileGuidance: "Using beads CLI for task management - plan file serves as context only",
|
|
7616
|
-
metadata: {
|
|
7617
|
-
phase: context.phase,
|
|
7618
|
-
planFilePath: context.conversationContext.planFilePath,
|
|
7619
|
-
transitionReason: context.transitionReason,
|
|
7620
|
-
isModeled: context.isModeled
|
|
7621
|
-
}
|
|
7622
|
-
};
|
|
7623
|
-
}
|
|
7624
|
-
/**
|
|
7625
|
-
* Apply variable substitution to instructions
|
|
7626
|
-
*/
|
|
7627
|
-
applyVariableSubstitution(instructions, projectPath, gitBranch) {
|
|
7628
|
-
const substitutions = this.projectDocsManager.getVariableSubstitutions(
|
|
7629
|
-
projectPath,
|
|
7630
|
-
gitBranch
|
|
7631
|
-
);
|
|
7632
|
-
let result = instructions;
|
|
7633
|
-
for (const [variable, value] of Object.entries(substitutions)) {
|
|
7634
|
-
result = result.replace(
|
|
7635
|
-
new RegExp(this.escapeRegExp(variable), "g"),
|
|
7636
|
-
value
|
|
7637
|
-
);
|
|
7638
|
-
}
|
|
7639
|
-
return result;
|
|
7640
|
-
}
|
|
7641
|
-
/**
|
|
7642
|
-
* Escape special regex characters in variable names
|
|
7643
|
-
*/
|
|
7644
|
-
escapeRegExp(string) {
|
|
7645
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7646
|
-
}
|
|
7647
|
-
/**
|
|
7648
|
-
* Enhance instructions with beads-specific guidance
|
|
7649
|
-
*/
|
|
7650
|
-
async enhanceBeadsInstructions(baseInstructions, context) {
|
|
7651
|
-
const { planFileExists } = context;
|
|
7652
|
-
const beadsTaskGuidance = await this.generateBeadsCLIGuidance(context);
|
|
7653
|
-
let enhanced = `${baseInstructions}
|
|
7654
|
-
|
|
7655
|
-
**Plan File Guidance:**
|
|
7656
|
-
Use the plan file as memory for the current objective
|
|
7657
|
-
- Update the "Key Decisions" section with important choices made
|
|
7658
|
-
- Add relevant notes to help maintain context
|
|
7659
|
-
- Do NOT enter tasks in the plan file, use beads CLI exclusively for task management
|
|
7660
|
-
|
|
7661
|
-
${beadsTaskGuidance}`;
|
|
7662
|
-
if (!planFileExists) {
|
|
7663
|
-
enhanced += "\n\n**Note**: Plan file will be created when you first update it.";
|
|
7664
|
-
}
|
|
7665
|
-
enhanced += `
|
|
7666
|
-
|
|
7667
|
-
**Important Reminders:**
|
|
7668
|
-
- Use ONLY bd CLI tool for task management - do not use your own task management tools
|
|
7669
|
-
- Call whats_next() after the next user message to maintain the development workflow`;
|
|
7670
|
-
return enhanced;
|
|
7671
|
-
}
|
|
7672
|
-
/**
|
|
7673
|
-
* Generate beads-specific task management guidance
|
|
7674
|
-
*/
|
|
7675
|
-
async generateBeadsCLIGuidance(context) {
|
|
7676
|
-
const { instructionSource } = context;
|
|
7677
|
-
if (instructionSource === "whats_next") {
|
|
7678
|
-
let additionalInstructions = `**bd Task Management:**
|
|
7679
|
-
`;
|
|
7680
|
-
const phaseTaskId = await this.extractPhaseTaskId(context);
|
|
7681
|
-
if (!phaseTaskId) {
|
|
7682
|
-
return additionalInstructions + `- Use bd CLI tool exclusively
|
|
7683
|
-
- **Start by listing ready tasks**: \`bd list --parent <phase-task-id> --status open\`
|
|
7684
|
-
- **Create new tasks**: \`bd create 'Task title' --parent <phase-task-id> -p <priority>\`
|
|
7685
|
-
- **Update status when working**: \`bd update <task-id> --status in_progress\`
|
|
7686
|
-
- **Complete tasks**: \`bd close <task-id>\`
|
|
7687
|
-
- **Focus on ready tasks first** - let beads handle dependencies
|
|
7688
|
-
- Add new tasks as they are identified during your work with the user`;
|
|
7689
|
-
}
|
|
7690
|
-
return additionalInstructions + `
|
|
7691
|
-
**Focus on subtasks of \`${phaseTaskId}\`**:
|
|
7692
|
-
\u2022 \`bd list --parent ${phaseTaskId} --status open\` - List ready work items
|
|
7693
|
-
\u2022 \`bd update <task-id> --status in_progress\` - Start working on a specific task
|
|
7694
|
-
\u2022 \`bd close <task-id>\` - Mark task complete when finished
|
|
7695
|
-
|
|
7696
|
-
**New Tasks for Current Phase**:
|
|
7697
|
-
\u2022 \`bd create 'Task description' --parent ${phaseTaskId} -p <priority>\` - Create work item under current phase
|
|
7698
|
-
\u2022 \`bd dep add <task-id> <depends-on-id>\` - Define dependencies for a task:`;
|
|
7699
|
-
}
|
|
7700
|
-
return "";
|
|
7701
|
-
}
|
|
7702
|
-
async extractPhaseTaskId(context) {
|
|
7703
|
-
try {
|
|
7704
|
-
const { readFile: readFile6 } = await import("fs/promises");
|
|
7705
|
-
const content = await readFile6(
|
|
7706
|
-
context.conversationContext.planFilePath,
|
|
7707
|
-
"utf-8"
|
|
7708
|
-
);
|
|
7709
|
-
const phaseName = this.capitalizePhase(context.phase);
|
|
7710
|
-
const phaseHeader = `## ${phaseName}`;
|
|
7711
|
-
const phaseSection = content.split("\n");
|
|
7712
|
-
let foundPhaseHeader = false;
|
|
7713
|
-
for (const line of phaseSection) {
|
|
7714
|
-
if (line.trim() === phaseHeader) {
|
|
7715
|
-
foundPhaseHeader = true;
|
|
7716
|
-
continue;
|
|
7717
|
-
}
|
|
7718
|
-
if (foundPhaseHeader && line.includes("beads-phase-id:")) {
|
|
7719
|
-
const match = line.match(/beads-phase-id:\s*([\w\d.-]+)/);
|
|
7720
|
-
if (match) {
|
|
7721
|
-
return match[1] || null;
|
|
7722
|
-
}
|
|
7723
|
-
}
|
|
7724
|
-
if (foundPhaseHeader && line.startsWith("##") && line !== phaseHeader) {
|
|
7725
|
-
break;
|
|
7726
|
-
}
|
|
7727
|
-
}
|
|
7728
|
-
return null;
|
|
7729
|
-
} catch (_error) {
|
|
7730
|
-
return null;
|
|
7731
|
-
}
|
|
7732
|
-
}
|
|
7733
|
-
/**
|
|
7734
|
-
* Capitalize phase name for display
|
|
7735
|
-
*/
|
|
7736
|
-
capitalizePhase(phase) {
|
|
7737
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
7738
|
-
}
|
|
7739
|
-
};
|
|
7740
|
-
|
|
7741
7416
|
// src/server-config.ts
|
|
7742
|
-
var
|
|
7417
|
+
var logger15 = createLogger("ServerConfig");
|
|
7743
7418
|
async function initializeServerComponents(config = {}) {
|
|
7744
|
-
|
|
7419
|
+
logger15.debug("Initializing server components", {
|
|
7745
7420
|
config: JSON.stringify(config)
|
|
7746
7421
|
});
|
|
7747
7422
|
const projectPath = normalizeProjectPath(
|
|
7748
7423
|
config.projectPath || process.env.PROJECT_PATH
|
|
7749
7424
|
);
|
|
7750
|
-
|
|
7425
|
+
logger15.info("Using project path", {
|
|
7751
7426
|
projectPath,
|
|
7752
7427
|
source: config.projectPath ? "config" : process.env.PROJECT_PATH ? "env" : "default"
|
|
7753
7428
|
});
|
|
@@ -7764,11 +7439,11 @@ async function initializeServerComponents(config = {}) {
|
|
|
7764
7439
|
);
|
|
7765
7440
|
mcpServer.server.setRequestHandler(SetLevelRequestSchema, async (request) => {
|
|
7766
7441
|
const level = request.params.level;
|
|
7767
|
-
|
|
7768
|
-
|
|
7442
|
+
logger15.info("Setting logging level from MCP client", { level });
|
|
7443
|
+
setLoggingLevelFromString(level);
|
|
7769
7444
|
return {};
|
|
7770
7445
|
});
|
|
7771
|
-
|
|
7446
|
+
logger15.debug("Initializing core components");
|
|
7772
7447
|
const database = new FileStorage(
|
|
7773
7448
|
path4.join(projectPath, ".vibe", "conversation.sqlite")
|
|
7774
7449
|
);
|
|
@@ -7781,38 +7456,31 @@ async function initializeServerComponents(config = {}) {
|
|
|
7781
7456
|
const transitionEngine = new TransitionEngine(projectPath);
|
|
7782
7457
|
transitionEngine.setConversationManager(conversationManager);
|
|
7783
7458
|
const taskBackendConfig = TaskBackendManager.detectTaskBackend();
|
|
7784
|
-
|
|
7785
|
-
logger24.info("Task backend configuration", {
|
|
7459
|
+
logger15.info("Task backend configuration", {
|
|
7786
7460
|
backend: taskBackendConfig.backend,
|
|
7787
7461
|
isAvailable: taskBackendConfig.isAvailable,
|
|
7788
7462
|
autoDetected: !process.env["TASK_BACKEND"]
|
|
7789
7463
|
});
|
|
7790
|
-
const planManager =
|
|
7791
|
-
const instructionGenerator =
|
|
7464
|
+
const planManager = new PlanManager();
|
|
7465
|
+
const instructionGenerator = new InstructionGenerator();
|
|
7792
7466
|
const interactionLogger = new InteractionLogger(database);
|
|
7793
7467
|
const pluginRegistry = new PluginRegistry();
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
enabled: beadsPlugin.isEnabled(),
|
|
7811
|
-
sequence: beadsPlugin.getSequence(),
|
|
7812
|
-
autoDetected: !process.env["TASK_BACKEND"]
|
|
7813
|
-
});
|
|
7814
|
-
}
|
|
7815
|
-
}
|
|
7468
|
+
const commitPlugin = new CommitPlugin({ projectPath });
|
|
7469
|
+
pluginRegistry.registerPlugin(commitPlugin);
|
|
7470
|
+
logger15.info("CommitPlugin registered", {
|
|
7471
|
+
enabled: commitPlugin.isEnabled(),
|
|
7472
|
+
sequence: commitPlugin.getSequence(),
|
|
7473
|
+
behavior: process.env.COMMIT_BEHAVIOR || "(not set)"
|
|
7474
|
+
});
|
|
7475
|
+
const beadsPlugin = new BeadsPlugin({ projectPath });
|
|
7476
|
+
pluginRegistry.registerPlugin(beadsPlugin);
|
|
7477
|
+
logger15.info("BeadsPlugin registered", {
|
|
7478
|
+
enabled: beadsPlugin.isEnabled(),
|
|
7479
|
+
sequence: beadsPlugin.getSequence(),
|
|
7480
|
+
backend: taskBackendConfig.backend,
|
|
7481
|
+
isAvailable: taskBackendConfig.isAvailable,
|
|
7482
|
+
autoDetected: !process.env["TASK_BACKEND"]
|
|
7483
|
+
});
|
|
7816
7484
|
const context = {
|
|
7817
7485
|
conversationManager,
|
|
7818
7486
|
transitionEngine,
|
|
@@ -7825,7 +7493,7 @@ async function initializeServerComponents(config = {}) {
|
|
|
7825
7493
|
};
|
|
7826
7494
|
await database.initialize();
|
|
7827
7495
|
workflowManager.loadProjectWorkflows(projectPath);
|
|
7828
|
-
|
|
7496
|
+
logger15.info("Server components initialized successfully");
|
|
7829
7497
|
return {
|
|
7830
7498
|
mcpServer,
|
|
7831
7499
|
database,
|
|
@@ -7848,7 +7516,7 @@ function createToolHandler(toolName, toolRegistry, responseRenderer, context) {
|
|
|
7848
7516
|
};
|
|
7849
7517
|
}
|
|
7850
7518
|
async function registerMcpTools(mcpServer, toolRegistry, responseRenderer, context) {
|
|
7851
|
-
|
|
7519
|
+
logger15.debug("Registering MCP tools");
|
|
7852
7520
|
notificationService.setMcpServer(mcpServer);
|
|
7853
7521
|
mcpServer.registerTool(
|
|
7854
7522
|
"whats_next",
|
|
@@ -8048,7 +7716,7 @@ async function registerMcpTools(mcpServer, toolRegistry, responseRenderer, conte
|
|
|
8048
7716
|
mcpServer.registerTool(
|
|
8049
7717
|
"setup_project_docs",
|
|
8050
7718
|
{
|
|
8051
|
-
description:
|
|
7719
|
+
description: "Create or link project docs (architecture.md, requirements.md, design.md). Use template names or file paths.",
|
|
8052
7720
|
inputSchema: {
|
|
8053
7721
|
architecture: z.string().default("freestyle").describe(
|
|
8054
7722
|
`Architecture documentation: template name (${availableTemplates.architecture.join(", ")}, none) OR file path to existing document`
|
|
@@ -8095,12 +7763,12 @@ async function registerMcpTools(mcpServer, toolRegistry, responseRenderer, conte
|
|
|
8095
7763
|
},
|
|
8096
7764
|
createToolHandler("no_idea", toolRegistry, responseRenderer, context)
|
|
8097
7765
|
);
|
|
8098
|
-
|
|
7766
|
+
logger15.info("MCP tools registered successfully", {
|
|
8099
7767
|
tools: toolRegistry.list()
|
|
8100
7768
|
});
|
|
8101
7769
|
}
|
|
8102
7770
|
function registerMcpResources(mcpServer, resourceRegistry, responseRenderer, context) {
|
|
8103
|
-
|
|
7771
|
+
logger15.debug("Registering MCP resources");
|
|
8104
7772
|
mcpServer.resource(
|
|
8105
7773
|
"Current Development Plan",
|
|
8106
7774
|
"plan://current",
|
|
@@ -8233,7 +7901,7 @@ function registerMcpResources(mcpServer, resourceRegistry, responseRenderer, con
|
|
|
8233
7901
|
};
|
|
8234
7902
|
}
|
|
8235
7903
|
);
|
|
8236
|
-
|
|
7904
|
+
logger15.info("MCP resources registered successfully", {
|
|
8237
7905
|
resources: ["plan://current", "state://current", "system-prompt://"],
|
|
8238
7906
|
resourceTemplates: ["workflow://{name}"]
|
|
8239
7907
|
});
|
|
@@ -8250,18 +7918,22 @@ var BaseToolHandler = class {
|
|
|
8250
7918
|
*/
|
|
8251
7919
|
async handle(args, context) {
|
|
8252
7920
|
const handlerName = this.constructor.name;
|
|
8253
|
-
|
|
7921
|
+
if (context.loggerFactory) {
|
|
7922
|
+
this.logger = context.loggerFactory(handlerName);
|
|
7923
|
+
}
|
|
7924
|
+
logHandlerExecution(handlerName, args, this.logger);
|
|
8254
7925
|
const result = await safeExecute(
|
|
8255
7926
|
() => this.executeHandler(args, context),
|
|
8256
|
-
`${handlerName} execution failed
|
|
7927
|
+
`${handlerName} execution failed`,
|
|
7928
|
+
this.logger
|
|
8257
7929
|
);
|
|
8258
7930
|
if (!result.success && result.error?.includes("CONVERSATION_NOT_FOUND")) {
|
|
8259
7931
|
const availableWorkflows = context.workflowManager.getWorkflowNames();
|
|
8260
7932
|
const helpfulError = createConversationNotFoundResult(availableWorkflows);
|
|
8261
|
-
logHandlerCompletion(handlerName, helpfulError);
|
|
7933
|
+
logHandlerCompletion(handlerName, helpfulError, this.logger);
|
|
8262
7934
|
return helpfulError;
|
|
8263
7935
|
}
|
|
8264
|
-
logHandlerCompletion(handlerName, result);
|
|
7936
|
+
logHandlerCompletion(handlerName, result, this.logger);
|
|
8265
7937
|
return result;
|
|
8266
7938
|
}
|
|
8267
7939
|
/**
|
|
@@ -8397,6 +8069,12 @@ var WhatsNextHandler = class extends ConversationRequiredToolHandler {
|
|
|
8397
8069
|
const planInfo = await context.planManager.getPlanFileInfo(
|
|
8398
8070
|
conversationContext.planFilePath
|
|
8399
8071
|
);
|
|
8072
|
+
const stateMachine = context.workflowManager.loadWorkflowForProject(
|
|
8073
|
+
conversationContext.projectPath,
|
|
8074
|
+
conversationContext.workflowName
|
|
8075
|
+
);
|
|
8076
|
+
const phaseState = stateMachine.states[transitionResult.newPhase];
|
|
8077
|
+
const allowedFilePatterns = phaseState?.allowed_file_patterns ?? ["**/*"];
|
|
8400
8078
|
const instructions = await context.instructionGenerator.generateInstructions(
|
|
8401
8079
|
transitionResult.instructions,
|
|
8402
8080
|
{
|
|
@@ -8407,14 +8085,40 @@ var WhatsNextHandler = class extends ConversationRequiredToolHandler {
|
|
|
8407
8085
|
},
|
|
8408
8086
|
transitionReason: transitionResult.transitionReason,
|
|
8409
8087
|
isModeled: transitionResult.isModeled,
|
|
8410
|
-
|
|
8411
|
-
|
|
8088
|
+
instructionSource: "whats_next",
|
|
8089
|
+
allowedFilePatterns
|
|
8412
8090
|
}
|
|
8413
8091
|
);
|
|
8092
|
+
let finalInstructions = instructions.instructions;
|
|
8093
|
+
if (context.pluginRegistry?.hasHook("afterInstructionsGenerated")) {
|
|
8094
|
+
const hookContext = {
|
|
8095
|
+
conversationId,
|
|
8096
|
+
planFilePath: conversationContext.planFilePath,
|
|
8097
|
+
currentPhase: transitionResult.newPhase,
|
|
8098
|
+
workflow: conversationContext.workflowName,
|
|
8099
|
+
projectPath: conversationContext.projectPath,
|
|
8100
|
+
gitBranch: conversationContext.gitBranch,
|
|
8101
|
+
planFileExists: planInfo.exists
|
|
8102
|
+
};
|
|
8103
|
+
const enriched = await context.pluginRegistry.executeHook(
|
|
8104
|
+
"afterInstructionsGenerated",
|
|
8105
|
+
hookContext,
|
|
8106
|
+
{
|
|
8107
|
+
instructions: instructions.instructions,
|
|
8108
|
+
planFilePath: conversationContext.planFilePath,
|
|
8109
|
+
phase: transitionResult.newPhase,
|
|
8110
|
+
instructionSource: "whats_next"
|
|
8111
|
+
}
|
|
8112
|
+
);
|
|
8113
|
+
if (enriched && typeof enriched === "object" && "instructions" in enriched) {
|
|
8114
|
+
finalInstructions = enriched.instructions;
|
|
8115
|
+
}
|
|
8116
|
+
}
|
|
8414
8117
|
const response = {
|
|
8415
8118
|
phase: transitionResult.newPhase,
|
|
8416
|
-
instructions:
|
|
8417
|
-
plan_file_path: conversationContext.planFilePath
|
|
8119
|
+
instructions: finalInstructions,
|
|
8120
|
+
plan_file_path: conversationContext.planFilePath,
|
|
8121
|
+
allowed_file_patterns: allowedFilePatterns
|
|
8418
8122
|
};
|
|
8419
8123
|
await this.logInteraction(
|
|
8420
8124
|
context,
|
|
@@ -8459,8 +8163,6 @@ var WhatsNextHandler = class extends ConversationRequiredToolHandler {
|
|
|
8459
8163
|
}
|
|
8460
8164
|
return true;
|
|
8461
8165
|
}
|
|
8462
|
-
// Beads-specific instruction logic has been moved to BeadsInstructionGenerator strategy
|
|
8463
|
-
// Utility methods moved to strategy implementations where needed
|
|
8464
8166
|
};
|
|
8465
8167
|
|
|
8466
8168
|
// src/tool-handlers/proceed-to-phase.ts
|
|
@@ -8494,6 +8196,9 @@ var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
|
8494
8196
|
conversationContext.projectPath,
|
|
8495
8197
|
context
|
|
8496
8198
|
);
|
|
8199
|
+
const prePlanInfo = await context.planManager.getPlanFileInfo(
|
|
8200
|
+
conversationContext.planFilePath
|
|
8201
|
+
);
|
|
8497
8202
|
const pluginContext = {
|
|
8498
8203
|
conversationId,
|
|
8499
8204
|
planFilePath: conversationContext.planFilePath,
|
|
@@ -8501,6 +8206,7 @@ var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
|
8501
8206
|
workflow: conversationContext.workflowName,
|
|
8502
8207
|
projectPath: conversationContext.projectPath,
|
|
8503
8208
|
gitBranch: conversationContext.gitBranch,
|
|
8209
|
+
planFileExists: prePlanInfo.exists,
|
|
8504
8210
|
targetPhase: target_phase
|
|
8505
8211
|
};
|
|
8506
8212
|
if (context.pluginRegistry) {
|
|
@@ -8535,6 +8241,12 @@ var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
|
8535
8241
|
const planInfo = await context.planManager.getPlanFileInfo(
|
|
8536
8242
|
conversationContext.planFilePath
|
|
8537
8243
|
);
|
|
8244
|
+
const stateMachine = context.workflowManager.loadWorkflowForProject(
|
|
8245
|
+
conversationContext.projectPath,
|
|
8246
|
+
conversationContext.workflowName
|
|
8247
|
+
);
|
|
8248
|
+
const phaseState = stateMachine.states[transitionResult.newPhase];
|
|
8249
|
+
const allowedFilePatterns = phaseState?.allowed_file_patterns ?? ["**/*"];
|
|
8538
8250
|
const instructions = await context.instructionGenerator.generateInstructions(
|
|
8539
8251
|
transitionResult.instructions,
|
|
8540
8252
|
{
|
|
@@ -8545,20 +8257,42 @@ var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
|
8545
8257
|
},
|
|
8546
8258
|
transitionReason: transitionResult.transitionReason,
|
|
8547
8259
|
isModeled: transitionResult.isModeled,
|
|
8548
|
-
|
|
8549
|
-
|
|
8260
|
+
instructionSource: "proceed_to_phase",
|
|
8261
|
+
allowedFilePatterns
|
|
8550
8262
|
}
|
|
8551
8263
|
);
|
|
8552
|
-
instructions.instructions
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8264
|
+
let finalInstructions = instructions.instructions;
|
|
8265
|
+
if (context.pluginRegistry?.hasHook("afterInstructionsGenerated")) {
|
|
8266
|
+
const hookContext = {
|
|
8267
|
+
conversationId,
|
|
8268
|
+
planFilePath: conversationContext.planFilePath,
|
|
8269
|
+
currentPhase: transitionResult.newPhase,
|
|
8270
|
+
workflow: conversationContext.workflowName,
|
|
8271
|
+
projectPath: conversationContext.projectPath,
|
|
8272
|
+
gitBranch: conversationContext.gitBranch,
|
|
8273
|
+
planFileExists: planInfo.exists
|
|
8274
|
+
};
|
|
8275
|
+
const enriched = await context.pluginRegistry.executeHook(
|
|
8276
|
+
"afterInstructionsGenerated",
|
|
8277
|
+
hookContext,
|
|
8278
|
+
{
|
|
8279
|
+
instructions: instructions.instructions,
|
|
8280
|
+
planFilePath: conversationContext.planFilePath,
|
|
8281
|
+
phase: transitionResult.newPhase,
|
|
8282
|
+
instructionSource: "proceed_to_phase"
|
|
8283
|
+
}
|
|
8284
|
+
);
|
|
8285
|
+
if (enriched && typeof enriched === "object" && "instructions" in enriched) {
|
|
8286
|
+
finalInstructions = enriched.instructions;
|
|
8287
|
+
}
|
|
8288
|
+
}
|
|
8289
|
+
finalInstructions += ` Review tasks for ${transitionResult.newPhase} phase, add missing ones based on key decisions.`;
|
|
8557
8290
|
const response = {
|
|
8558
8291
|
phase: transitionResult.newPhase,
|
|
8559
|
-
instructions:
|
|
8292
|
+
instructions: finalInstructions,
|
|
8560
8293
|
plan_file_path: conversationContext.planFilePath,
|
|
8561
|
-
transition_reason: transitionResult.transitionReason
|
|
8294
|
+
transition_reason: transitionResult.transitionReason,
|
|
8295
|
+
allowed_file_patterns: allowedFilePatterns
|
|
8562
8296
|
};
|
|
8563
8297
|
await this.logInteraction(
|
|
8564
8298
|
context,
|
|
@@ -8725,23 +8459,17 @@ var ConductReviewHandler = class extends ConversationRequiredToolHandler {
|
|
|
8725
8459
|
* Generate instructions for LLM to conduct guided review
|
|
8726
8460
|
*/
|
|
8727
8461
|
async generateReviewInstructions(perspectives, currentPhase, targetPhase) {
|
|
8728
|
-
const
|
|
8462
|
+
const perspectiveDetails = perspectives.map(
|
|
8463
|
+
(p, i) => `${i + 1}. **${p.perspective.toUpperCase()}**: ${p.prompt}`
|
|
8464
|
+
).join("\n");
|
|
8465
|
+
const instructions = `Review ${currentPhase} phase before proceeding to ${targetPhase}.
|
|
8729
8466
|
|
|
8730
|
-
|
|
8731
|
-
1. Reviewing the plan file to see completed tasks and key decisions
|
|
8732
|
-
2. Using git status/diff to see what files were changed (if in a git repository)
|
|
8733
|
-
3. Analyzing recent conversation history for important decisions
|
|
8467
|
+
**Check:** plan file (tasks/decisions), git diff (changes), conversation history.
|
|
8734
8468
|
|
|
8735
|
-
|
|
8469
|
+
**Perspectives:**
|
|
8470
|
+
${perspectiveDetails}
|
|
8736
8471
|
|
|
8737
|
-
|
|
8738
|
-
(p, i) => `**${i + 1}. ${p.perspective.toUpperCase()} PERSPECTIVE:**
|
|
8739
|
-
${p.prompt}
|
|
8740
|
-
|
|
8741
|
-
`
|
|
8742
|
-
).join("")}
|
|
8743
|
-
|
|
8744
|
-
After completing all perspective reviews, summarize your findings and ask the user if they're ready to proceed to the ${targetPhase} phase.`;
|
|
8472
|
+
Summarize findings and ask user if ready to proceed.`;
|
|
8745
8473
|
return {
|
|
8746
8474
|
instructions,
|
|
8747
8475
|
perspectives: perspectives.map((p) => ({
|
|
@@ -8755,18 +8483,21 @@ After completing all perspective reviews, summarize your findings and ask the us
|
|
|
8755
8483
|
// src/tool-handlers/start-development.ts
|
|
8756
8484
|
import { basename as basename4 } from "path";
|
|
8757
8485
|
import { readFileSync, writeFileSync, existsSync as existsSync3, mkdirSync } from "fs";
|
|
8758
|
-
import { readFile as
|
|
8486
|
+
import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
8759
8487
|
import { resolve as resolve3 } from "path";
|
|
8760
|
-
var logger25 = createLogger("StartDevelopmentHandler");
|
|
8761
8488
|
var StartDevelopmentHandler = class extends BaseToolHandler {
|
|
8762
|
-
projectDocsManager;
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8489
|
+
projectDocsManager = null;
|
|
8490
|
+
getProjectDocsManager() {
|
|
8491
|
+
if (!this.projectDocsManager) {
|
|
8492
|
+
this.projectDocsManager = new ProjectDocsManager(this.logger);
|
|
8493
|
+
}
|
|
8494
|
+
return this.projectDocsManager;
|
|
8766
8495
|
}
|
|
8767
8496
|
async executeHandler(args, context) {
|
|
8768
8497
|
validateRequiredArgs(args, ["workflow"]);
|
|
8769
|
-
const taskBackendConfig = TaskBackendManager.validateTaskBackend(
|
|
8498
|
+
const taskBackendConfig = TaskBackendManager.validateTaskBackend(
|
|
8499
|
+
this.logger
|
|
8500
|
+
);
|
|
8770
8501
|
const selectedWorkflow = args.workflow;
|
|
8771
8502
|
const requireReviews = args.require_reviews ?? false;
|
|
8772
8503
|
const projectPath = stripVibePathSuffix(
|
|
@@ -8800,12 +8531,10 @@ var StartDevelopmentHandler = class extends BaseToolHandler {
|
|
|
8800
8531
|
const suggestedBranchName = this.generateBranchSuggestion();
|
|
8801
8532
|
const branchPromptResponse = {
|
|
8802
8533
|
phase: "branch-prompt",
|
|
8803
|
-
instructions: `
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
Please create a new branch and then call start_development again to begin development.`,
|
|
8808
|
-
plan_file_path: ""
|
|
8534
|
+
instructions: `On ${currentBranch}. Create feature branch: \`git checkout -b ${suggestedBranchName}\`, then retry \`start_development\`.`,
|
|
8535
|
+
plan_file_path: "",
|
|
8536
|
+
allowed_file_patterns: ["**/*"]
|
|
8537
|
+
// Allow all files during branch prompt
|
|
8809
8538
|
};
|
|
8810
8539
|
this.logger.debug(
|
|
8811
8540
|
"User on main/master branch, prompting for branch creation",
|
|
@@ -8863,6 +8592,8 @@ Please create a new branch and then call start_development again to begin develo
|
|
|
8863
8592
|
workflow: selectedWorkflow,
|
|
8864
8593
|
projectPath,
|
|
8865
8594
|
gitBranch: conversationContext.gitBranch,
|
|
8595
|
+
planFileExists: true,
|
|
8596
|
+
// we just created/ensured the plan file exists
|
|
8866
8597
|
stateMachine: {
|
|
8867
8598
|
name: stateMachine.name,
|
|
8868
8599
|
description: stateMachine.description,
|
|
@@ -8872,7 +8603,7 @@ Please create a new branch and then call start_development again to begin develo
|
|
|
8872
8603
|
};
|
|
8873
8604
|
if (context.pluginRegistry) {
|
|
8874
8605
|
try {
|
|
8875
|
-
const originalContent = await
|
|
8606
|
+
const originalContent = await readFile4(
|
|
8876
8607
|
conversationContext.planFilePath,
|
|
8877
8608
|
"utf-8"
|
|
8878
8609
|
);
|
|
@@ -8883,14 +8614,14 @@ Please create a new branch and then call start_development again to begin develo
|
|
|
8883
8614
|
originalContent
|
|
8884
8615
|
);
|
|
8885
8616
|
if (modifiedContent && modifiedContent !== originalContent) {
|
|
8886
|
-
await
|
|
8617
|
+
await writeFile4(
|
|
8887
8618
|
conversationContext.planFilePath,
|
|
8888
8619
|
modifiedContent,
|
|
8889
8620
|
"utf-8"
|
|
8890
8621
|
);
|
|
8891
8622
|
}
|
|
8892
8623
|
} catch (error) {
|
|
8893
|
-
|
|
8624
|
+
this.logger.debug("Could not execute afterPlanFileCreated hook", {
|
|
8894
8625
|
error: error instanceof Error ? error.message : String(error),
|
|
8895
8626
|
planFilePath: conversationContext.planFilePath
|
|
8896
8627
|
});
|
|
@@ -8915,30 +8646,33 @@ Please create a new branch and then call start_development again to begin develo
|
|
|
8915
8646
|
}
|
|
8916
8647
|
this.ensureGitignoreEntry(projectPath);
|
|
8917
8648
|
const workflowDocumentationUrl = this.generateWorkflowDocumentationUrl(selectedWorkflow);
|
|
8918
|
-
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
|
|
8649
|
+
let finalInstructions = context.planManager.getInitialPlanGuidance(
|
|
8650
|
+
conversationContext.planFilePath,
|
|
8651
|
+
workflowDocumentationUrl
|
|
8652
|
+
);
|
|
8653
|
+
const phaseState = stateMachine.states[transitionResult.newPhase];
|
|
8654
|
+
const allowedFilePatterns = phaseState?.allowed_file_patterns ?? ["**/*"];
|
|
8655
|
+
if (context.pluginRegistry?.hasHook("afterInstructionsGenerated")) {
|
|
8656
|
+
const enriched = await context.pluginRegistry.executeHook(
|
|
8657
|
+
"afterInstructionsGenerated",
|
|
8658
|
+
pluginContext,
|
|
8659
|
+
{
|
|
8660
|
+
instructions: finalInstructions,
|
|
8661
|
+
planFilePath: conversationContext.planFilePath,
|
|
8662
|
+
phase: transitionResult.newPhase,
|
|
8663
|
+
instructionSource: "start_development"
|
|
8664
|
+
}
|
|
8665
|
+
);
|
|
8666
|
+
if (enriched && typeof enriched === "object" && "instructions" in enriched) {
|
|
8667
|
+
finalInstructions = enriched.instructions;
|
|
8668
|
+
}
|
|
8669
|
+
}
|
|
8937
8670
|
const response = {
|
|
8938
8671
|
phase: transitionResult.newPhase,
|
|
8939
8672
|
instructions: finalInstructions,
|
|
8940
8673
|
plan_file_path: conversationContext.planFilePath,
|
|
8941
|
-
workflowDocumentationUrl
|
|
8674
|
+
workflowDocumentationUrl,
|
|
8675
|
+
allowed_file_patterns: allowedFilePatterns
|
|
8942
8676
|
};
|
|
8943
8677
|
await this.logInteraction(
|
|
8944
8678
|
context,
|
|
@@ -8980,7 +8714,7 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
8980
8714
|
);
|
|
8981
8715
|
return null;
|
|
8982
8716
|
}
|
|
8983
|
-
const docsInfo = await this.
|
|
8717
|
+
const docsInfo = await this.getProjectDocsManager().getProjectDocsInfo(projectPath);
|
|
8984
8718
|
const missingDocs = this.getMissingReferencedDocuments(
|
|
8985
8719
|
referencedVariables,
|
|
8986
8720
|
docsInfo,
|
|
@@ -8998,9 +8732,7 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
8998
8732
|
}
|
|
8999
8733
|
const setupGuidance = await this.generateArtifactSetupGuidance(
|
|
9000
8734
|
missingDocs,
|
|
9001
|
-
workflowName
|
|
9002
|
-
docsInfo,
|
|
9003
|
-
referencedVariables
|
|
8735
|
+
workflowName
|
|
9004
8736
|
);
|
|
9005
8737
|
this.logger.info(
|
|
9006
8738
|
"Missing required project artifacts detected for workflow that requires documentation",
|
|
@@ -9012,10 +8744,17 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
9012
8744
|
projectPath
|
|
9013
8745
|
}
|
|
9014
8746
|
);
|
|
8747
|
+
const initialPhase = stateMachine.initial_state;
|
|
8748
|
+
const initialPhaseState = stateMachine.states[initialPhase];
|
|
8749
|
+
const allowedFilePatterns = initialPhaseState?.allowed_file_patterns ?? [
|
|
8750
|
+
"**/*"
|
|
8751
|
+
];
|
|
9015
8752
|
return {
|
|
9016
8753
|
phase: "artifact-setup",
|
|
9017
8754
|
instructions: setupGuidance,
|
|
9018
|
-
plan_file_path: ""
|
|
8755
|
+
plan_file_path: "",
|
|
8756
|
+
// Use the initial phase's file restrictions during artifact setup
|
|
8757
|
+
allowed_file_patterns: allowedFilePatterns
|
|
9019
8758
|
};
|
|
9020
8759
|
} catch (error) {
|
|
9021
8760
|
this.logger.warn(
|
|
@@ -9032,7 +8771,7 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
9032
8771
|
* Analyze workflow content to detect document variable references
|
|
9033
8772
|
*/
|
|
9034
8773
|
analyzeWorkflowDocumentReferences(stateMachine, projectPath) {
|
|
9035
|
-
const variableSubstitutions = this.
|
|
8774
|
+
const variableSubstitutions = this.getProjectDocsManager().getVariableSubstitutions(projectPath);
|
|
9036
8775
|
const documentVariables = Object.keys(variableSubstitutions);
|
|
9037
8776
|
const referencedVariables = /* @__PURE__ */ new Set();
|
|
9038
8777
|
const workflowContent = JSON.stringify(stateMachine);
|
|
@@ -9053,7 +8792,10 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
9053
8792
|
*/
|
|
9054
8793
|
getMissingReferencedDocuments(referencedVariables, docsInfo, projectPath) {
|
|
9055
8794
|
const missingDocs = [];
|
|
9056
|
-
const variableSubstitutions = this.
|
|
8795
|
+
const variableSubstitutions = this.getProjectDocsManager().getVariableSubstitutions(
|
|
8796
|
+
projectPath,
|
|
8797
|
+
void 0
|
|
8798
|
+
);
|
|
9057
8799
|
const variableToDocMap = {};
|
|
9058
8800
|
for (const [variable, path6] of Object.entries(variableSubstitutions)) {
|
|
9059
8801
|
const filename = basename4(path6);
|
|
@@ -9074,115 +8816,15 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
9074
8816
|
/**
|
|
9075
8817
|
* Generate guidance for setting up missing project artifacts
|
|
9076
8818
|
*/
|
|
9077
|
-
async generateArtifactSetupGuidance(missingDocs, workflowName
|
|
9078
|
-
const
|
|
9079
|
-
|
|
9080
|
-
if (docsInfo.architecture.exists) {
|
|
9081
|
-
const fileName = basename4(docsInfo.architecture.path);
|
|
9082
|
-
existingDocs.push(`\u2705 ${fileName}`);
|
|
9083
|
-
}
|
|
9084
|
-
if (docsInfo.requirements.exists) {
|
|
9085
|
-
const fileName = basename4(docsInfo.requirements.path);
|
|
9086
|
-
existingDocs.push(`\u2705 ${fileName}`);
|
|
9087
|
-
}
|
|
9088
|
-
if (docsInfo.design.exists) {
|
|
9089
|
-
const fileName = basename4(docsInfo.design.path);
|
|
9090
|
-
existingDocs.push(`\u2705 ${fileName}`);
|
|
9091
|
-
}
|
|
9092
|
-
const existingList = existingDocs.length > 0 ? `
|
|
9093
|
-
|
|
9094
|
-
**Existing Documents:**
|
|
9095
|
-
${existingDocs.join("\n")}` : "";
|
|
9096
|
-
const referencedVariablesList = referencedVariables.map((v) => `\`${v}\``).join(", ");
|
|
9097
|
-
const availableTemplates = await this.projectDocsManager.templateManager.getAvailableTemplates();
|
|
9098
|
-
const defaults = await this.projectDocsManager.templateManager.getDefaults();
|
|
9099
|
-
const templateOptionsText = this.generateTemplateOptionsText(availableTemplates);
|
|
9100
|
-
return `## Project Documentation Setup Required
|
|
8819
|
+
async generateArtifactSetupGuidance(missingDocs, workflowName) {
|
|
8820
|
+
const availableTemplates = await this.getProjectDocsManager().templateManager.getAvailableTemplates();
|
|
8821
|
+
return `Missing docs for **${workflowName}**: ${missingDocs.join(", ")}
|
|
9101
8822
|
|
|
9102
|
-
|
|
8823
|
+
Run \`setup_project_docs()\` with templates: ${Object.entries(
|
|
8824
|
+
availableTemplates
|
|
8825
|
+
).map(([type2, templates]) => `${type2}: ${templates.join("/")}`).join("; ")}
|
|
9103
8826
|
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
**Missing Documents:**
|
|
9107
|
-
${missingList}${existingList}
|
|
9108
|
-
|
|
9109
|
-
## \u{1F680} **Quick Setup**
|
|
9110
|
-
|
|
9111
|
-
Use the \`setup_project_docs\` tool to create these documents with templates:
|
|
9112
|
-
|
|
9113
|
-
\`\`\`
|
|
9114
|
-
setup_project_docs({
|
|
9115
|
-
architecture: "${defaults.architecture}", // or other available options
|
|
9116
|
-
requirements: "${defaults.requirements}", // or other available options
|
|
9117
|
-
design: "${defaults.design}" // or other available options
|
|
9118
|
-
})
|
|
9119
|
-
\`\`\`
|
|
9120
|
-
|
|
9121
|
-
${templateOptionsText}
|
|
9122
|
-
|
|
9123
|
-
## \u26A1 **Next Steps**
|
|
9124
|
-
|
|
9125
|
-
1. **Call \`setup_project_docs\`** with your preferred templates
|
|
9126
|
-
2. **Call \`start_development\`** again to begin the ${workflowName} workflow
|
|
9127
|
-
3. The workflow will reference these documents using the detected variables: ${referencedVariablesList}
|
|
9128
|
-
|
|
9129
|
-
**Note:** You can also proceed without structured docs, but the workflow instructions will reference missing files.`;
|
|
9130
|
-
}
|
|
9131
|
-
/**
|
|
9132
|
-
* Generate template options text dynamically
|
|
9133
|
-
*/
|
|
9134
|
-
generateTemplateOptionsText(availableTemplates) {
|
|
9135
|
-
const sections = [];
|
|
9136
|
-
if (availableTemplates.architecture.length > 0) {
|
|
9137
|
-
const archOptions = availableTemplates.architecture.map((template) => {
|
|
9138
|
-
const description = this.getTemplateDescription(
|
|
9139
|
-
template,
|
|
9140
|
-
"architecture"
|
|
9141
|
-
);
|
|
9142
|
-
return `- **${template}**: ${description}`;
|
|
9143
|
-
}).join("\n");
|
|
9144
|
-
sections.push(`**Architecture Templates:**
|
|
9145
|
-
${archOptions}`);
|
|
9146
|
-
}
|
|
9147
|
-
if (availableTemplates.requirements.length > 0) {
|
|
9148
|
-
const reqOptions = availableTemplates.requirements.map((template) => {
|
|
9149
|
-
const description = this.getTemplateDescription(
|
|
9150
|
-
template,
|
|
9151
|
-
"requirements"
|
|
9152
|
-
);
|
|
9153
|
-
return `- **${template}**: ${description}`;
|
|
9154
|
-
}).join("\n");
|
|
9155
|
-
sections.push(`**Requirements Templates:**
|
|
9156
|
-
${reqOptions}`);
|
|
9157
|
-
}
|
|
9158
|
-
if (availableTemplates.design.length > 0) {
|
|
9159
|
-
const designOptions = availableTemplates.design.map((template) => {
|
|
9160
|
-
const description = this.getTemplateDescription(template, "design");
|
|
9161
|
-
return `- **${template}**: ${description}`;
|
|
9162
|
-
}).join("\n");
|
|
9163
|
-
sections.push(`**Design Templates:**
|
|
9164
|
-
${designOptions}`);
|
|
9165
|
-
}
|
|
9166
|
-
return sections.length > 0 ? `## \u{1F4CB} **Template Options**
|
|
9167
|
-
|
|
9168
|
-
${sections.join("\n\n")}` : "";
|
|
9169
|
-
}
|
|
9170
|
-
/**
|
|
9171
|
-
* Get description for a template based on its name and type
|
|
9172
|
-
*/
|
|
9173
|
-
getTemplateDescription(template, type2) {
|
|
9174
|
-
switch (template) {
|
|
9175
|
-
case "arc42":
|
|
9176
|
-
return "Comprehensive software architecture template with diagrams";
|
|
9177
|
-
case "ears":
|
|
9178
|
-
return "WHEN...THEN format for clear, testable requirements";
|
|
9179
|
-
case "comprehensive":
|
|
9180
|
-
return "Full implementation guide with testing strategy";
|
|
9181
|
-
case "freestyle":
|
|
9182
|
-
return `Simple, flexible ${type2} documentation`;
|
|
9183
|
-
default:
|
|
9184
|
-
return `${template} format for ${type2} documentation`;
|
|
9185
|
-
}
|
|
8827
|
+
Then retry \`start_development\`.`;
|
|
9186
8828
|
}
|
|
9187
8829
|
/**
|
|
9188
8830
|
* Generate workflow documentation URL for predefined workflows
|
|
@@ -9544,12 +9186,12 @@ var ResetDevelopmentHandler = class extends BaseToolHandler {
|
|
|
9544
9186
|
|
|
9545
9187
|
// src/tool-handlers/list-workflows.ts
|
|
9546
9188
|
import { z as z2 } from "zod";
|
|
9547
|
-
var
|
|
9189
|
+
var logger16 = createLogger("ListWorkflowsHandler");
|
|
9548
9190
|
var ListWorkflowsArgsSchema = z2.object({});
|
|
9549
9191
|
var ListWorkflowsHandler = class extends BaseToolHandler {
|
|
9550
9192
|
argsSchema = ListWorkflowsArgsSchema;
|
|
9551
9193
|
async executeHandler(_args, context) {
|
|
9552
|
-
|
|
9194
|
+
logger16.info("Listing available workflows", {
|
|
9553
9195
|
projectPath: context.projectPath
|
|
9554
9196
|
});
|
|
9555
9197
|
const availableWorkflows = context.workflowManager.getAvailableWorkflowsForProject(
|
|
@@ -9564,7 +9206,7 @@ var ListWorkflowsHandler = class extends BaseToolHandler {
|
|
|
9564
9206
|
const response = {
|
|
9565
9207
|
workflows
|
|
9566
9208
|
};
|
|
9567
|
-
|
|
9209
|
+
logger16.info("Successfully listed workflows", {
|
|
9568
9210
|
count: workflows.length,
|
|
9569
9211
|
workflows: workflows.map((w) => w.name)
|
|
9570
9212
|
});
|
|
@@ -9578,13 +9220,13 @@ import { z as z3 } from "zod";
|
|
|
9578
9220
|
// src/version-info.ts
|
|
9579
9221
|
import { execSync as execSync6 } from "child_process";
|
|
9580
9222
|
import { readFileSync as readFileSync2 } from "fs";
|
|
9581
|
-
import { join as join8, dirname as
|
|
9223
|
+
import { join as join8, dirname as dirname6 } from "path";
|
|
9582
9224
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
9583
|
-
var
|
|
9225
|
+
var logger17 = createLogger("VersionInfo");
|
|
9584
9226
|
var BUILD_TIME_VERSION = null;
|
|
9585
9227
|
function getVersionFromPackageJson() {
|
|
9586
9228
|
try {
|
|
9587
|
-
const currentDir =
|
|
9229
|
+
const currentDir = dirname6(fileURLToPath4(import.meta.url));
|
|
9588
9230
|
const packageJsonPaths = [
|
|
9589
9231
|
join8(currentDir, "..", "package.json"),
|
|
9590
9232
|
join8(currentDir, "..", "..", "..", "package.json")
|
|
@@ -9593,7 +9235,7 @@ function getVersionFromPackageJson() {
|
|
|
9593
9235
|
try {
|
|
9594
9236
|
const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
|
|
9595
9237
|
if (packageJson.version) {
|
|
9596
|
-
|
|
9238
|
+
logger17.debug("Found version in package.json", {
|
|
9597
9239
|
path: packageJsonPath,
|
|
9598
9240
|
version: packageJson.version
|
|
9599
9241
|
});
|
|
@@ -9603,7 +9245,7 @@ function getVersionFromPackageJson() {
|
|
|
9603
9245
|
};
|
|
9604
9246
|
}
|
|
9605
9247
|
} catch (error) {
|
|
9606
|
-
|
|
9248
|
+
logger17.debug("Could not read package.json", {
|
|
9607
9249
|
path: packageJsonPath,
|
|
9608
9250
|
error: error instanceof Error ? error.message : String(error)
|
|
9609
9251
|
});
|
|
@@ -9611,7 +9253,7 @@ function getVersionFromPackageJson() {
|
|
|
9611
9253
|
}
|
|
9612
9254
|
return null;
|
|
9613
9255
|
} catch (error) {
|
|
9614
|
-
|
|
9256
|
+
logger17.debug("Error getting version from package.json", { error });
|
|
9615
9257
|
return null;
|
|
9616
9258
|
}
|
|
9617
9259
|
}
|
|
@@ -9621,7 +9263,7 @@ function getVersionFromGit() {
|
|
|
9621
9263
|
encoding: "utf-8",
|
|
9622
9264
|
stdio: "pipe"
|
|
9623
9265
|
}).trim();
|
|
9624
|
-
|
|
9266
|
+
logger17.debug("Git describe output", { gitDescribe });
|
|
9625
9267
|
const isDirty = gitDescribe.endsWith("-dirty");
|
|
9626
9268
|
const cleanDescribe = isDirty ? gitDescribe.slice(0, -6) : gitDescribe;
|
|
9627
9269
|
const parts = cleanDescribe.split("-");
|
|
@@ -9646,16 +9288,16 @@ function getVersionFromGit() {
|
|
|
9646
9288
|
source: "git"
|
|
9647
9289
|
};
|
|
9648
9290
|
} catch (error) {
|
|
9649
|
-
|
|
9291
|
+
logger17.debug("Error getting version from git", {
|
|
9650
9292
|
error: error instanceof Error ? error.message : String(error)
|
|
9651
9293
|
});
|
|
9652
9294
|
return null;
|
|
9653
9295
|
}
|
|
9654
9296
|
}
|
|
9655
9297
|
function getVersionInfo() {
|
|
9656
|
-
|
|
9298
|
+
logger17.debug("Determining version information");
|
|
9657
9299
|
if (BUILD_TIME_VERSION) {
|
|
9658
|
-
|
|
9300
|
+
logger17.info("Using build-time version information", {
|
|
9659
9301
|
version: BUILD_TIME_VERSION.version,
|
|
9660
9302
|
source: BUILD_TIME_VERSION.source
|
|
9661
9303
|
});
|
|
@@ -9665,7 +9307,7 @@ function getVersionInfo() {
|
|
|
9665
9307
|
if (gitVersion) {
|
|
9666
9308
|
const packageVersion2 = getVersionFromPackageJson();
|
|
9667
9309
|
if (packageVersion2 && gitVersion.version === "unknown") {
|
|
9668
|
-
|
|
9310
|
+
logger17.info("Using package.json version with git commit info", {
|
|
9669
9311
|
version: packageVersion2.version,
|
|
9670
9312
|
commit: gitVersion.commit || "unknown",
|
|
9671
9313
|
isDirty: String(gitVersion.isDirty || false)
|
|
@@ -9676,7 +9318,7 @@ function getVersionInfo() {
|
|
|
9676
9318
|
source: "git"
|
|
9677
9319
|
};
|
|
9678
9320
|
}
|
|
9679
|
-
|
|
9321
|
+
logger17.info("Using git version information", {
|
|
9680
9322
|
version: gitVersion.version,
|
|
9681
9323
|
source: gitVersion.source,
|
|
9682
9324
|
commit: gitVersion.commit || "none",
|
|
@@ -9686,13 +9328,13 @@ function getVersionInfo() {
|
|
|
9686
9328
|
}
|
|
9687
9329
|
const packageVersion = getVersionFromPackageJson();
|
|
9688
9330
|
if (packageVersion) {
|
|
9689
|
-
|
|
9331
|
+
logger17.info("Using package.json version information", {
|
|
9690
9332
|
version: packageVersion.version,
|
|
9691
9333
|
source: packageVersion.source
|
|
9692
9334
|
});
|
|
9693
9335
|
return packageVersion;
|
|
9694
9336
|
}
|
|
9695
|
-
|
|
9337
|
+
logger17.warn("Could not determine version information, using fallback");
|
|
9696
9338
|
return {
|
|
9697
9339
|
version: "unknown",
|
|
9698
9340
|
source: "fallback"
|
|
@@ -9711,14 +9353,14 @@ function getFormattedVersion() {
|
|
|
9711
9353
|
}
|
|
9712
9354
|
|
|
9713
9355
|
// src/tool-handlers/get-tool-info.ts
|
|
9714
|
-
var
|
|
9356
|
+
var logger18 = createLogger("GetToolInfoHandler");
|
|
9715
9357
|
var GetToolInfoArgsSchema = z3.object({
|
|
9716
9358
|
// No input parameters needed
|
|
9717
9359
|
});
|
|
9718
9360
|
var GetToolInfoHandler = class extends BaseToolHandler {
|
|
9719
9361
|
argsSchema = GetToolInfoArgsSchema;
|
|
9720
9362
|
async executeHandler(_args, context) {
|
|
9721
|
-
|
|
9363
|
+
logger18.info("Generating comprehensive tool information", {
|
|
9722
9364
|
projectPath: context.projectPath
|
|
9723
9365
|
});
|
|
9724
9366
|
const availableWorkflows = context.workflowManager.getAvailableWorkflowsForProject(
|
|
@@ -9808,7 +9450,7 @@ var GetToolInfoHandler = class extends BaseToolHandler {
|
|
|
9808
9450
|
plan_file_path: conversationContext.planFilePath
|
|
9809
9451
|
};
|
|
9810
9452
|
} catch (error) {
|
|
9811
|
-
|
|
9453
|
+
logger18.debug("No active conversation found for workflow state", {
|
|
9812
9454
|
error
|
|
9813
9455
|
});
|
|
9814
9456
|
}
|
|
@@ -9835,7 +9477,7 @@ var GetToolInfoHandler = class extends BaseToolHandler {
|
|
|
9835
9477
|
if (workflowState) {
|
|
9836
9478
|
response.workflow_states = workflowState;
|
|
9837
9479
|
}
|
|
9838
|
-
|
|
9480
|
+
logger18.info("Successfully generated tool information", {
|
|
9839
9481
|
toolCount: tools.length,
|
|
9840
9482
|
workflowCount: workflows.length,
|
|
9841
9483
|
hasWorkflowState: !!workflowState
|
|
@@ -9855,22 +9497,25 @@ var GetToolInfoHandler = class extends BaseToolHandler {
|
|
|
9855
9497
|
|
|
9856
9498
|
// src/tool-handlers/setup-project-docs.ts
|
|
9857
9499
|
var SetupProjectDocsHandler = class extends BaseToolHandler {
|
|
9858
|
-
projectDocsManager;
|
|
9859
|
-
|
|
9860
|
-
|
|
9861
|
-
|
|
9500
|
+
projectDocsManager = null;
|
|
9501
|
+
getProjectDocsManager() {
|
|
9502
|
+
if (!this.projectDocsManager) {
|
|
9503
|
+
this.projectDocsManager = new ProjectDocsManager(this.logger);
|
|
9504
|
+
}
|
|
9505
|
+
return this.projectDocsManager;
|
|
9862
9506
|
}
|
|
9863
9507
|
async executeHandler(args, context) {
|
|
9864
9508
|
const projectPath = stripVibePathSuffix(
|
|
9865
9509
|
args.project_path,
|
|
9866
9510
|
context.projectPath || process.cwd()
|
|
9867
9511
|
);
|
|
9512
|
+
const projectDocsManager = this.getProjectDocsManager();
|
|
9868
9513
|
this.logger.info(
|
|
9869
9514
|
"Setting up project docs with enhanced file linking support",
|
|
9870
9515
|
{ args, projectPath }
|
|
9871
9516
|
);
|
|
9872
9517
|
try {
|
|
9873
|
-
const availableTemplates = await
|
|
9518
|
+
const availableTemplates = await projectDocsManager.templateManager.getAvailableTemplates();
|
|
9874
9519
|
const processedArgs = await this.validateAndProcessArgs(
|
|
9875
9520
|
args,
|
|
9876
9521
|
availableTemplates,
|
|
@@ -9882,7 +9527,7 @@ var SetupProjectDocsHandler = class extends BaseToolHandler {
|
|
|
9882
9527
|
created: [],
|
|
9883
9528
|
linked: [],
|
|
9884
9529
|
skipped: [],
|
|
9885
|
-
paths:
|
|
9530
|
+
paths: projectDocsManager.getDocumentPaths(projectPath),
|
|
9886
9531
|
message: processedArgs.error || "Unknown error during validation"
|
|
9887
9532
|
};
|
|
9888
9533
|
}
|
|
@@ -9891,12 +9536,12 @@ var SetupProjectDocsHandler = class extends BaseToolHandler {
|
|
|
9891
9536
|
"Invalid processed args: missing templateOptions or filePaths"
|
|
9892
9537
|
);
|
|
9893
9538
|
}
|
|
9894
|
-
const result = await
|
|
9539
|
+
const result = await projectDocsManager.createOrLinkProjectDocs(
|
|
9895
9540
|
projectPath,
|
|
9896
9541
|
processedArgs.templateOptions,
|
|
9897
9542
|
processedArgs.filePaths
|
|
9898
9543
|
);
|
|
9899
|
-
const paths =
|
|
9544
|
+
const paths = projectDocsManager.getDocumentPaths(projectPath);
|
|
9900
9545
|
let message = "Project documentation setup completed.";
|
|
9901
9546
|
if (result.created.length > 0) {
|
|
9902
9547
|
message += ` Created: ${result.created.join(", ")}.`;
|
|
@@ -9931,7 +9576,7 @@ var SetupProjectDocsHandler = class extends BaseToolHandler {
|
|
|
9931
9576
|
created: [],
|
|
9932
9577
|
linked: [],
|
|
9933
9578
|
skipped: [],
|
|
9934
|
-
paths:
|
|
9579
|
+
paths: projectDocsManager.getDocumentPaths(projectPath),
|
|
9935
9580
|
message: `Failed to setup project docs: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
9936
9581
|
};
|
|
9937
9582
|
}
|
|
@@ -10009,11 +9654,11 @@ var NoIdeaHandler = class extends BaseToolHandler {
|
|
|
10009
9654
|
};
|
|
10010
9655
|
|
|
10011
9656
|
// src/tool-handlers/index.ts
|
|
10012
|
-
var
|
|
9657
|
+
var logger19 = createLogger("ToolRegistry");
|
|
10013
9658
|
var DefaultToolRegistry = class {
|
|
10014
9659
|
handlers = /* @__PURE__ */ new Map();
|
|
10015
9660
|
register(name, handler) {
|
|
10016
|
-
|
|
9661
|
+
logger19.debug("Registering tool handler", {
|
|
10017
9662
|
name,
|
|
10018
9663
|
handlerType: handler.constructor.name
|
|
10019
9664
|
});
|
|
@@ -10038,17 +9683,24 @@ function createToolRegistry() {
|
|
|
10038
9683
|
registry.register("get_tool_info", new GetToolInfoHandler());
|
|
10039
9684
|
registry.register("setup_project_docs", new SetupProjectDocsHandler());
|
|
10040
9685
|
registry.register("no_idea", new NoIdeaHandler());
|
|
10041
|
-
|
|
9686
|
+
logger19.info("Tool registry created with handlers", {
|
|
10042
9687
|
handlers: registry.list()
|
|
10043
9688
|
});
|
|
10044
9689
|
return registry;
|
|
10045
9690
|
}
|
|
10046
9691
|
|
|
10047
9692
|
// src/resource-handlers/development-plan.ts
|
|
10048
|
-
var
|
|
9693
|
+
var defaultLogger8 = createLogger("DevelopmentPlanResourceHandler");
|
|
10049
9694
|
var DevelopmentPlanResourceHandler = class {
|
|
9695
|
+
logger;
|
|
9696
|
+
constructor(logger24) {
|
|
9697
|
+
this.logger = logger24 ?? defaultLogger8;
|
|
9698
|
+
}
|
|
10050
9699
|
async handle(uri, context) {
|
|
10051
|
-
|
|
9700
|
+
if (context.loggerFactory) {
|
|
9701
|
+
this.logger = context.loggerFactory("DevelopmentPlanResourceHandler");
|
|
9702
|
+
}
|
|
9703
|
+
this.logger.debug("Processing development plan resource request", {
|
|
10052
9704
|
uri: uri.href
|
|
10053
9705
|
});
|
|
10054
9706
|
return safeExecute(async () => {
|
|
@@ -10066,10 +9718,17 @@ var DevelopmentPlanResourceHandler = class {
|
|
|
10066
9718
|
};
|
|
10067
9719
|
|
|
10068
9720
|
// src/resource-handlers/conversation-state.ts
|
|
10069
|
-
var
|
|
9721
|
+
var defaultLogger9 = createLogger("ConversationStateResourceHandler");
|
|
10070
9722
|
var ConversationStateResourceHandler = class {
|
|
9723
|
+
logger;
|
|
9724
|
+
constructor(logger24) {
|
|
9725
|
+
this.logger = logger24 ?? defaultLogger9;
|
|
9726
|
+
}
|
|
10071
9727
|
async handle(uri, context) {
|
|
10072
|
-
|
|
9728
|
+
if (context.loggerFactory) {
|
|
9729
|
+
this.logger = context.loggerFactory("ConversationStateResourceHandler");
|
|
9730
|
+
}
|
|
9731
|
+
this.logger.debug("Processing conversation state resource request", {
|
|
10073
9732
|
uri: uri.href
|
|
10074
9733
|
});
|
|
10075
9734
|
return safeExecute(async () => {
|
|
@@ -10096,10 +9755,19 @@ var ConversationStateResourceHandler = class {
|
|
|
10096
9755
|
import fs5 from "fs";
|
|
10097
9756
|
import path5 from "path";
|
|
10098
9757
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
10099
|
-
var
|
|
9758
|
+
var defaultLogger10 = createLogger("WorkflowResourceHandler");
|
|
10100
9759
|
var WorkflowResourceHandler = class {
|
|
9760
|
+
logger;
|
|
9761
|
+
constructor(logger24) {
|
|
9762
|
+
this.logger = logger24 ?? defaultLogger10;
|
|
9763
|
+
}
|
|
10101
9764
|
async handle(uri, context) {
|
|
10102
|
-
|
|
9765
|
+
if (context.loggerFactory) {
|
|
9766
|
+
this.logger = context.loggerFactory("WorkflowResourceHandler");
|
|
9767
|
+
}
|
|
9768
|
+
this.logger.debug("Processing workflow resource request", {
|
|
9769
|
+
uri: uri.href
|
|
9770
|
+
});
|
|
10103
9771
|
return safeExecute(async () => {
|
|
10104
9772
|
const workflowName = uri.hostname;
|
|
10105
9773
|
if (!workflowName) {
|
|
@@ -10107,7 +9775,10 @@ var WorkflowResourceHandler = class {
|
|
|
10107
9775
|
"Invalid workflow URI: missing workflow name. Expected: workflow://workflow-name"
|
|
10108
9776
|
);
|
|
10109
9777
|
}
|
|
10110
|
-
|
|
9778
|
+
this.logger.info("Loading workflow resource", {
|
|
9779
|
+
workflowName,
|
|
9780
|
+
uri: uri.href
|
|
9781
|
+
});
|
|
10111
9782
|
let yamlContent;
|
|
10112
9783
|
let filePath;
|
|
10113
9784
|
const workflow = context.workflowManager.getWorkflow(workflowName);
|
|
@@ -10137,7 +9808,7 @@ var WorkflowResourceHandler = class {
|
|
|
10137
9808
|
`${workflowName}.yml`
|
|
10138
9809
|
);
|
|
10139
9810
|
if (!fs5.existsSync(workflowFileYml)) {
|
|
10140
|
-
|
|
9811
|
+
this.logger.error(
|
|
10141
9812
|
"Workflow file not found",
|
|
10142
9813
|
new Error(`Workflow '${workflowName}' not found`),
|
|
10143
9814
|
{
|
|
@@ -10161,7 +9832,7 @@ var WorkflowResourceHandler = class {
|
|
|
10161
9832
|
filePath = workflowFile;
|
|
10162
9833
|
}
|
|
10163
9834
|
yamlContent = fs5.readFileSync(filePath, "utf-8");
|
|
10164
|
-
|
|
9835
|
+
this.logger.info("Successfully loaded workflow resource", {
|
|
10165
9836
|
workflowName,
|
|
10166
9837
|
filePath,
|
|
10167
9838
|
contentLength: yamlContent.length
|
|
@@ -10176,17 +9847,24 @@ var WorkflowResourceHandler = class {
|
|
|
10176
9847
|
};
|
|
10177
9848
|
|
|
10178
9849
|
// src/resource-handlers/system-prompt.ts
|
|
10179
|
-
var
|
|
9850
|
+
var defaultLogger11 = createLogger("SystemPromptResourceHandler");
|
|
10180
9851
|
var SystemPromptResourceHandler = class {
|
|
10181
|
-
|
|
10182
|
-
|
|
9852
|
+
logger;
|
|
9853
|
+
constructor(logger24) {
|
|
9854
|
+
this.logger = logger24 ?? defaultLogger11;
|
|
9855
|
+
}
|
|
9856
|
+
async handle(uri, context) {
|
|
9857
|
+
if (context.loggerFactory) {
|
|
9858
|
+
this.logger = context.loggerFactory("SystemPromptResourceHandler");
|
|
9859
|
+
}
|
|
9860
|
+
this.logger.debug("Processing system prompt resource request", {
|
|
10183
9861
|
uri: uri.href
|
|
10184
9862
|
});
|
|
10185
9863
|
return safeExecute(async () => {
|
|
10186
9864
|
const loader2 = new StateMachineLoader();
|
|
10187
9865
|
const stateMachine = loader2.loadStateMachine(process.cwd());
|
|
10188
9866
|
const systemPrompt = generateSystemPrompt(stateMachine);
|
|
10189
|
-
|
|
9867
|
+
this.logger.debug("Generated system prompt for resource", {
|
|
10190
9868
|
promptLength: systemPrompt.length,
|
|
10191
9869
|
workflowName: stateMachine.name
|
|
10192
9870
|
});
|
|
@@ -10200,11 +9878,11 @@ var SystemPromptResourceHandler = class {
|
|
|
10200
9878
|
};
|
|
10201
9879
|
|
|
10202
9880
|
// src/resource-handlers/index.ts
|
|
10203
|
-
var
|
|
9881
|
+
var logger20 = createLogger("ResourceRegistry");
|
|
10204
9882
|
var DefaultResourceRegistry = class {
|
|
10205
9883
|
handlers = /* @__PURE__ */ new Map();
|
|
10206
9884
|
register(pattern, handler) {
|
|
10207
|
-
|
|
9885
|
+
logger20.debug("Registering resource handler", {
|
|
10208
9886
|
pattern,
|
|
10209
9887
|
handlerType: handler.constructor.name
|
|
10210
9888
|
});
|
|
@@ -10213,11 +9891,11 @@ var DefaultResourceRegistry = class {
|
|
|
10213
9891
|
resolve(uri) {
|
|
10214
9892
|
for (const [pattern, handler] of this.handlers.entries()) {
|
|
10215
9893
|
if (uri.includes(pattern)) {
|
|
10216
|
-
|
|
9894
|
+
logger20.debug("Resolved resource handler", { uri, pattern });
|
|
10217
9895
|
return handler;
|
|
10218
9896
|
}
|
|
10219
9897
|
}
|
|
10220
|
-
|
|
9898
|
+
logger20.debug("No resource handler found for URI", { uri });
|
|
10221
9899
|
return void 0;
|
|
10222
9900
|
}
|
|
10223
9901
|
};
|
|
@@ -10227,7 +9905,7 @@ function createResourceRegistry() {
|
|
|
10227
9905
|
registry.register("state://current", new ConversationStateResourceHandler());
|
|
10228
9906
|
registry.register("workflow://", new WorkflowResourceHandler());
|
|
10229
9907
|
registry.register("system-prompt://", new SystemPromptResourceHandler());
|
|
10230
|
-
|
|
9908
|
+
logger20.info("Resource registry created with handlers", {
|
|
10231
9909
|
patterns: [
|
|
10232
9910
|
"plan://current",
|
|
10233
9911
|
"state://current",
|
|
@@ -10239,13 +9917,13 @@ function createResourceRegistry() {
|
|
|
10239
9917
|
}
|
|
10240
9918
|
|
|
10241
9919
|
// src/response-renderer.ts
|
|
10242
|
-
var
|
|
9920
|
+
var logger21 = createLogger("ResponseRenderer");
|
|
10243
9921
|
var DefaultResponseRenderer = class {
|
|
10244
9922
|
/**
|
|
10245
9923
|
* Render a tool handler result as an MCP tool response
|
|
10246
9924
|
*/
|
|
10247
9925
|
renderToolResponse(result) {
|
|
10248
|
-
|
|
9926
|
+
logger21.debug("Rendering tool response", {
|
|
10249
9927
|
success: result.success,
|
|
10250
9928
|
hasData: !!result.data,
|
|
10251
9929
|
hasError: !!result.error
|
|
@@ -10267,7 +9945,7 @@ var DefaultResponseRenderer = class {
|
|
|
10267
9945
|
* Render a resource handler result as an MCP resource response
|
|
10268
9946
|
*/
|
|
10269
9947
|
renderResourceResponse(result) {
|
|
10270
|
-
|
|
9948
|
+
logger21.debug("Rendering resource response", {
|
|
10271
9949
|
success: result.success,
|
|
10272
9950
|
hasData: !!result.data
|
|
10273
9951
|
});
|
|
@@ -10298,7 +9976,7 @@ var DefaultResponseRenderer = class {
|
|
|
10298
9976
|
*/
|
|
10299
9977
|
renderError(error) {
|
|
10300
9978
|
const errorMessage = error instanceof Error ? error.message : error;
|
|
10301
|
-
|
|
9979
|
+
logger21.debug("Rendering error response", { errorMessage });
|
|
10302
9980
|
return {
|
|
10303
9981
|
content: [
|
|
10304
9982
|
{
|
|
@@ -10314,8 +9992,53 @@ function createResponseRenderer() {
|
|
|
10314
9992
|
return new DefaultResponseRenderer();
|
|
10315
9993
|
}
|
|
10316
9994
|
|
|
9995
|
+
// src/mcp-log-sink.ts
|
|
9996
|
+
function capitalizePhase2(phase) {
|
|
9997
|
+
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
9998
|
+
}
|
|
9999
|
+
function createMcpLogSink(mcpServer) {
|
|
10000
|
+
return {
|
|
10001
|
+
async log(level, logger24, message, context) {
|
|
10002
|
+
try {
|
|
10003
|
+
let enhancedMessage = message;
|
|
10004
|
+
let notificationLevel = level;
|
|
10005
|
+
if (context && (context["from"] || context["to"]) && message.includes("transition")) {
|
|
10006
|
+
const from = context["from"] ? capitalizePhase2(context["from"]) : "";
|
|
10007
|
+
const to = context["to"] ? capitalizePhase2(context["to"]) : "";
|
|
10008
|
+
if (from && to) {
|
|
10009
|
+
enhancedMessage = `Phase Transition: ${from} \u2192 ${to}`;
|
|
10010
|
+
notificationLevel = "info";
|
|
10011
|
+
}
|
|
10012
|
+
}
|
|
10013
|
+
if (message.includes("initialized successfully")) {
|
|
10014
|
+
enhancedMessage = "\u{1F680} Vibe Feature MCP Server Ready";
|
|
10015
|
+
notificationLevel = "info";
|
|
10016
|
+
}
|
|
10017
|
+
let logData = enhancedMessage;
|
|
10018
|
+
if (context) {
|
|
10019
|
+
try {
|
|
10020
|
+
const contextStr = JSON.stringify(context, null, 0);
|
|
10021
|
+
logData = `${enhancedMessage} ${contextStr}`;
|
|
10022
|
+
} catch (_error) {
|
|
10023
|
+
logData = `${enhancedMessage} [context serialization failed]`;
|
|
10024
|
+
}
|
|
10025
|
+
}
|
|
10026
|
+
await mcpServer.server.notification({
|
|
10027
|
+
method: "notifications/message",
|
|
10028
|
+
params: {
|
|
10029
|
+
level: notificationLevel,
|
|
10030
|
+
logger: logger24,
|
|
10031
|
+
data: logData
|
|
10032
|
+
}
|
|
10033
|
+
});
|
|
10034
|
+
} catch (_error) {
|
|
10035
|
+
}
|
|
10036
|
+
}
|
|
10037
|
+
};
|
|
10038
|
+
}
|
|
10039
|
+
|
|
10317
10040
|
// src/server-implementation.ts
|
|
10318
|
-
var
|
|
10041
|
+
var logger22 = createLogger("ResponsibleVibeMCPServer");
|
|
10319
10042
|
async function createResponsibleVibeMCPServer(config = {}) {
|
|
10320
10043
|
const components = await initializeServerComponents(config);
|
|
10321
10044
|
return new ResponsibleVibeMCPServer(config, components);
|
|
@@ -10324,7 +10047,7 @@ var ResponsibleVibeMCPServer = class {
|
|
|
10324
10047
|
constructor(config, serverComponents) {
|
|
10325
10048
|
this.config = config;
|
|
10326
10049
|
this.serverComponents = serverComponents;
|
|
10327
|
-
|
|
10050
|
+
logger22.debug("ResponsibleVibeMCPServer created", {
|
|
10328
10051
|
config: JSON.stringify(this.config)
|
|
10329
10052
|
});
|
|
10330
10053
|
}
|
|
@@ -10333,7 +10056,7 @@ var ResponsibleVibeMCPServer = class {
|
|
|
10333
10056
|
* Initialize the server and all its components
|
|
10334
10057
|
*/
|
|
10335
10058
|
async initialize() {
|
|
10336
|
-
|
|
10059
|
+
logger22.debug("Initializing ResponsibleVibeMCPServer");
|
|
10337
10060
|
try {
|
|
10338
10061
|
this.components = this.serverComponents;
|
|
10339
10062
|
const toolRegistry = createToolRegistry();
|
|
@@ -10342,7 +10065,7 @@ var ResponsibleVibeMCPServer = class {
|
|
|
10342
10065
|
this.components.toolRegistry = toolRegistry;
|
|
10343
10066
|
this.components.resourceRegistry = resourceRegistry;
|
|
10344
10067
|
this.components.responseRenderer = responseRenderer;
|
|
10345
|
-
|
|
10068
|
+
registerLogSink(createMcpLogSink(this.components.mcpServer));
|
|
10346
10069
|
await registerMcpTools(
|
|
10347
10070
|
this.components.mcpServer,
|
|
10348
10071
|
toolRegistry,
|
|
@@ -10356,7 +10079,7 @@ var ResponsibleVibeMCPServer = class {
|
|
|
10356
10079
|
this.components.context
|
|
10357
10080
|
);
|
|
10358
10081
|
} catch (error) {
|
|
10359
|
-
|
|
10082
|
+
logger22.error(
|
|
10360
10083
|
"Failed to initialize ResponsibleVibeMCPServer",
|
|
10361
10084
|
error
|
|
10362
10085
|
);
|
|
@@ -10489,16 +10212,16 @@ var ResponsibleVibeMCPServer = class {
|
|
|
10489
10212
|
* Cleanup server resources
|
|
10490
10213
|
*/
|
|
10491
10214
|
async cleanup() {
|
|
10492
|
-
|
|
10215
|
+
logger22.debug("Cleaning up server resources");
|
|
10493
10216
|
if (this.components?.database) {
|
|
10494
10217
|
await this.components.database.close();
|
|
10495
10218
|
}
|
|
10496
|
-
|
|
10219
|
+
logger22.info("Server cleanup completed");
|
|
10497
10220
|
}
|
|
10498
10221
|
};
|
|
10499
10222
|
|
|
10500
10223
|
// src/index.ts
|
|
10501
|
-
var
|
|
10224
|
+
var logger23 = createLogger("Main");
|
|
10502
10225
|
function parseCliArgs() {
|
|
10503
10226
|
return { shouldStartServer: true };
|
|
10504
10227
|
}
|
|
@@ -10516,30 +10239,46 @@ async function main() {
|
|
|
10516
10239
|
const transport = new StdioServerTransport();
|
|
10517
10240
|
await server.getMcpServer().connect(transport);
|
|
10518
10241
|
process.on("SIGINT", async () => {
|
|
10519
|
-
|
|
10242
|
+
logger23.info("Shutting down Vibe Feature MCP Server...");
|
|
10520
10243
|
await server.cleanup();
|
|
10521
10244
|
process.exit(0);
|
|
10522
10245
|
});
|
|
10523
10246
|
process.on("SIGTERM", async () => {
|
|
10524
|
-
|
|
10247
|
+
logger23.info("Shutting down Vibe Feature MCP Server...");
|
|
10525
10248
|
await server.cleanup();
|
|
10526
10249
|
process.exit(0);
|
|
10527
10250
|
});
|
|
10528
10251
|
} catch (error) {
|
|
10529
|
-
|
|
10252
|
+
logger23.error("Failed to start server", error);
|
|
10530
10253
|
process.exit(1);
|
|
10531
10254
|
}
|
|
10532
10255
|
}
|
|
10533
10256
|
var isMainModule = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("ade-workflows-server") || process.argv[1]?.endsWith("index.js");
|
|
10534
10257
|
if (isMainModule) {
|
|
10535
10258
|
await main().catch((error) => {
|
|
10536
|
-
|
|
10259
|
+
logger23.error("Unhandled error in main", error);
|
|
10537
10260
|
process.exit(1);
|
|
10538
10261
|
});
|
|
10539
10262
|
}
|
|
10540
10263
|
export {
|
|
10264
|
+
BaseToolHandler,
|
|
10265
|
+
BeadsPlugin,
|
|
10266
|
+
ConductReviewHandler,
|
|
10267
|
+
ConversationRequiredToolHandler,
|
|
10268
|
+
DefaultToolRegistry,
|
|
10269
|
+
GetToolInfoHandler,
|
|
10270
|
+
ListWorkflowsHandler,
|
|
10271
|
+
NoIdeaHandler,
|
|
10272
|
+
PluginRegistry,
|
|
10273
|
+
ProceedToPhaseHandler,
|
|
10274
|
+
ResetDevelopmentHandler,
|
|
10541
10275
|
ResponsibleVibeMCPServer,
|
|
10276
|
+
ResumeWorkflowHandler,
|
|
10277
|
+
SetupProjectDocsHandler,
|
|
10278
|
+
StartDevelopmentHandler,
|
|
10279
|
+
WhatsNextHandler,
|
|
10542
10280
|
createResponsibleVibeMCPServer,
|
|
10281
|
+
createToolRegistry,
|
|
10543
10282
|
main as startMcpServer
|
|
10544
10283
|
};
|
|
10545
10284
|
/*! Bundled license information:
|