@codemcp/workflows 6.4.0 → 6.5.1
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 +220 -0
- package/packages/opencode-plugin/dist/index.js +28616 -0
- package/packages/opencode-plugin/package.json +55 -0
- package/packages/opencode-plugin/resources/agents/architect.yaml +61 -0
- package/packages/opencode-plugin/resources/agents/business-analyst.yaml +60 -0
- package/packages/opencode-plugin/resources/agents/developer.yaml +61 -0
- package/packages/opencode-plugin/resources/templates/architecture/arc42/arc42-template-EN.md +1077 -0
- package/packages/opencode-plugin/resources/templates/architecture/arc42/images/01_2_iso-25010-topics-EN.drawio-2023.png +0 -0
- package/packages/opencode-plugin/resources/templates/architecture/arc42/images/01_2_iso-25010-topics-EN.drawio.png +0 -0
- package/packages/opencode-plugin/resources/templates/architecture/arc42/images/05_building_blocks-EN.png +0 -0
- package/packages/opencode-plugin/resources/templates/architecture/arc42/images/08-concepts-EN.drawio.png +0 -0
- package/packages/opencode-plugin/resources/templates/architecture/arc42/images/arc42-logo.png +0 -0
- package/packages/opencode-plugin/resources/templates/architecture/c4.md +224 -0
- package/packages/opencode-plugin/resources/templates/architecture/freestyle.md +53 -0
- package/packages/opencode-plugin/resources/templates/architecture/game.md +250 -0
- package/packages/opencode-plugin/resources/templates/architecture/none.md +17 -0
- package/packages/opencode-plugin/resources/templates/design/comprehensive.md +207 -0
- package/packages/opencode-plugin/resources/templates/design/freestyle.md +37 -0
- package/packages/opencode-plugin/resources/templates/design/game.md +66 -0
- package/packages/opencode-plugin/resources/templates/design/none.md +17 -0
- package/packages/opencode-plugin/resources/templates/requirements/ears.md +90 -0
- package/packages/opencode-plugin/resources/templates/requirements/freestyle.md +42 -0
- package/packages/opencode-plugin/resources/templates/requirements/game.md +162 -0
- package/packages/opencode-plugin/resources/templates/requirements/none.md +17 -0
- package/packages/opencode-plugin/resources/templates/skills/POWER.md +23 -0
- package/packages/opencode-plugin/resources/templates/skills/SKILL.md +19 -0
- package/packages/opencode-plugin/resources/workflows/adr.yaml +157 -0
- package/packages/opencode-plugin/resources/workflows/big-bang-conversion.yaml +592 -0
- package/packages/opencode-plugin/resources/workflows/boundary-testing.yaml +376 -0
- package/packages/opencode-plugin/resources/workflows/bugfix.yaml +178 -0
- package/packages/opencode-plugin/resources/workflows/business-analysis.yaml +597 -0
- package/packages/opencode-plugin/resources/workflows/c4-analysis.yaml +471 -0
- package/packages/opencode-plugin/resources/workflows/epcc.yaml +195 -0
- package/packages/opencode-plugin/resources/workflows/game-beginner.yaml +434 -0
- package/packages/opencode-plugin/resources/workflows/greenfield.yaml +217 -0
- package/packages/opencode-plugin/resources/workflows/minor.yaml +146 -0
- package/packages/opencode-plugin/resources/workflows/posts.yaml +193 -0
- package/packages/opencode-plugin/resources/workflows/sdd-bugfix-crowd.yaml +608 -0
- package/packages/opencode-plugin/resources/workflows/sdd-bugfix.yaml +381 -0
- package/packages/opencode-plugin/resources/workflows/sdd-feature-crowd.yaml +713 -0
- package/packages/opencode-plugin/resources/workflows/sdd-feature.yaml +471 -0
- package/packages/opencode-plugin/resources/workflows/sdd-greenfield-crowd.yaml +336 -0
- package/packages/opencode-plugin/resources/workflows/sdd-greenfield.yaml +463 -0
- package/packages/opencode-plugin/resources/workflows/skilled-bugfix.yaml +174 -0
- package/packages/opencode-plugin/resources/workflows/skilled-epcc.yaml +171 -0
- package/packages/opencode-plugin/resources/workflows/skilled-greenfield.yaml +207 -0
- package/packages/opencode-plugin/resources/workflows/slides.yaml +237 -0
- package/packages/opencode-plugin/resources/workflows/tdd.yaml +170 -0
- package/packages/opencode-plugin/resources/workflows/waterfall.yaml +225 -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
|
@@ -4087,16 +4087,13 @@ import { SetLevelRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
|
4087
4087
|
import * as path4 from "path";
|
|
4088
4088
|
import { homedir } from "os";
|
|
4089
4089
|
import { execSync as execSync5 } from "child_process";
|
|
4090
|
-
import { writeFile as writeFile4, readFile as readFile4, access as access6 } from "fs/promises";
|
|
4091
|
-
import { dirname as dirname6 } from "path";
|
|
4092
|
-
import { mkdir as mkdir4 } from "fs/promises";
|
|
4093
4090
|
import { basename as basename4 } from "path";
|
|
4094
4091
|
import { readFileSync, writeFileSync, existsSync as existsSync3, mkdirSync } from "fs";
|
|
4095
|
-
import { readFile as
|
|
4092
|
+
import { readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
4096
4093
|
import { resolve as resolve3 } from "path";
|
|
4097
4094
|
import { execSync as execSync6 } from "child_process";
|
|
4098
4095
|
import { readFileSync as readFileSync2 } from "fs";
|
|
4099
|
-
import { join as join8, dirname as
|
|
4096
|
+
import { join as join8, dirname as dirname6 } from "path";
|
|
4100
4097
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
4101
4098
|
import fs5 from "fs";
|
|
4102
4099
|
import path5 from "path";
|
|
@@ -6737,25 +6734,21 @@ var LogLevel;
|
|
|
6737
6734
|
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
6738
6735
|
LogLevel2[LogLevel2["SILENT"] = 4] = "SILENT";
|
|
6739
6736
|
})(LogLevel || (LogLevel = {}));
|
|
6740
|
-
var
|
|
6737
|
+
var logSinkInstance = null;
|
|
6741
6738
|
var currentLoggingLevel = null;
|
|
6742
6739
|
function isTestMode() {
|
|
6743
|
-
if (process.env
|
|
6740
|
+
if (process.env["NODE_ENV"] === "test" || process.env["VITEST"] === "true") {
|
|
6744
6741
|
return true;
|
|
6745
6742
|
}
|
|
6746
|
-
|
|
6747
|
-
if (cwd.includes("/tmp/") || cwd.includes("temp") || cwd.includes("test-")) {
|
|
6748
|
-
return true;
|
|
6749
|
-
}
|
|
6750
|
-
if (process.env.LOG_LEVEL === "ERROR") {
|
|
6743
|
+
if (process.env["LOG_LEVEL"] === "ERROR") {
|
|
6751
6744
|
return true;
|
|
6752
6745
|
}
|
|
6753
6746
|
return false;
|
|
6754
6747
|
}
|
|
6755
|
-
function
|
|
6756
|
-
|
|
6748
|
+
function registerLogSink(sink) {
|
|
6749
|
+
logSinkInstance = sink;
|
|
6757
6750
|
}
|
|
6758
|
-
function
|
|
6751
|
+
function setLoggingLevelFromString(level) {
|
|
6759
6752
|
const levelMap = {
|
|
6760
6753
|
debug: LogLevel.DEBUG,
|
|
6761
6754
|
info: LogLevel.INFO,
|
|
@@ -6795,7 +6788,7 @@ var Logger = class _Logger {
|
|
|
6795
6788
|
return LogLevel.INFO;
|
|
6796
6789
|
}
|
|
6797
6790
|
getLogLevelFromEnv() {
|
|
6798
|
-
const envLevel = process.env
|
|
6791
|
+
const envLevel = process.env["LOG_LEVEL"]?.toUpperCase();
|
|
6799
6792
|
switch (envLevel) {
|
|
6800
6793
|
case "DEBUG":
|
|
6801
6794
|
return LogLevel.DEBUG;
|
|
@@ -6820,31 +6813,15 @@ var Logger = class _Logger {
|
|
|
6820
6813
|
return `[${timestamp2}] ${level.toUpperCase()} [${this.component}] ${message}${contextStr}`;
|
|
6821
6814
|
}
|
|
6822
6815
|
/**
|
|
6823
|
-
* Send log message to
|
|
6816
|
+
* Send log message to registered sink if available
|
|
6824
6817
|
*/
|
|
6825
|
-
async
|
|
6826
|
-
if (
|
|
6818
|
+
async sendToSink(level, message, context) {
|
|
6819
|
+
if (logSinkInstance) {
|
|
6827
6820
|
try {
|
|
6828
|
-
|
|
6829
|
-
if (context) {
|
|
6830
|
-
try {
|
|
6831
|
-
const contextStr = JSON.stringify(context, null, 0);
|
|
6832
|
-
logData = `${message} ${contextStr}`;
|
|
6833
|
-
} catch (_error) {
|
|
6834
|
-
logData = `${message} [context serialization failed]`;
|
|
6835
|
-
}
|
|
6836
|
-
}
|
|
6837
|
-
await mcpServerInstance.server.notification({
|
|
6838
|
-
method: "notifications/message",
|
|
6839
|
-
params: {
|
|
6840
|
-
level,
|
|
6841
|
-
logger: this.component,
|
|
6842
|
-
data: logData
|
|
6843
|
-
}
|
|
6844
|
-
});
|
|
6821
|
+
await logSinkInstance.log(level, this.component, message, context);
|
|
6845
6822
|
} catch (error) {
|
|
6846
6823
|
if (!isTestMode()) {
|
|
6847
|
-
process.stderr.write(`[
|
|
6824
|
+
process.stderr.write(`[LOG-SINK-ERROR] Failed to send log to sink: ${error}
|
|
6848
6825
|
`);
|
|
6849
6826
|
}
|
|
6850
6827
|
}
|
|
@@ -6852,85 +6829,42 @@ var Logger = class _Logger {
|
|
|
6852
6829
|
}
|
|
6853
6830
|
debug(message, context) {
|
|
6854
6831
|
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6832
|
+
if (!logSinkInstance) {
|
|
6833
|
+
const formattedMessage = this.formatMessage("debug", message, context);
|
|
6834
|
+
process.stderr.write(formattedMessage + "\n");
|
|
6835
|
+
}
|
|
6836
|
+
this.sendToSink("debug", message, context).catch(() => {
|
|
6858
6837
|
});
|
|
6859
6838
|
}
|
|
6860
6839
|
}
|
|
6861
6840
|
info(message, context) {
|
|
6862
6841
|
if (this.shouldLog(LogLevel.INFO)) {
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
});
|
|
6867
|
-
}
|
|
6868
|
-
}
|
|
6869
|
-
/**
|
|
6870
|
-
* Send enhanced MCP notifications with better formatting for important events
|
|
6871
|
-
*/
|
|
6872
|
-
async sendEnhancedMcpNotification(level, message, context) {
|
|
6873
|
-
if (mcpServerInstance) {
|
|
6874
|
-
try {
|
|
6875
|
-
let enhancedMessage = message;
|
|
6876
|
-
let notificationLevel = level;
|
|
6877
|
-
if (context && (context.from || context.to) && message.includes("transition")) {
|
|
6878
|
-
const from = context.from ? this.capitalizePhase(context.from) : "";
|
|
6879
|
-
const to = context.to ? this.capitalizePhase(context.to) : "";
|
|
6880
|
-
if (from && to) {
|
|
6881
|
-
enhancedMessage = `Phase Transition: ${from} \u2192 ${to}`;
|
|
6882
|
-
notificationLevel = "info";
|
|
6883
|
-
}
|
|
6884
|
-
}
|
|
6885
|
-
if (message.includes("initialized successfully")) {
|
|
6886
|
-
enhancedMessage = "\u{1F680} Vibe Feature MCP Server Ready";
|
|
6887
|
-
notificationLevel = "info";
|
|
6888
|
-
}
|
|
6889
|
-
let logData = enhancedMessage;
|
|
6890
|
-
if (context) {
|
|
6891
|
-
try {
|
|
6892
|
-
const contextStr = JSON.stringify(context, null, 0);
|
|
6893
|
-
logData = `${enhancedMessage} ${contextStr}`;
|
|
6894
|
-
} catch (_error) {
|
|
6895
|
-
logData = `${enhancedMessage} [context serialization failed]`;
|
|
6896
|
-
}
|
|
6897
|
-
}
|
|
6898
|
-
await mcpServerInstance.server.notification({
|
|
6899
|
-
method: "notifications/message",
|
|
6900
|
-
params: {
|
|
6901
|
-
level: notificationLevel,
|
|
6902
|
-
logger: this.component,
|
|
6903
|
-
data: logData
|
|
6904
|
-
}
|
|
6905
|
-
});
|
|
6906
|
-
} catch (error) {
|
|
6907
|
-
if (!isTestMode()) {
|
|
6908
|
-
process.stderr.write(`[MCP-LOG-ERROR] Failed to send log notification: ${error}
|
|
6909
|
-
`);
|
|
6910
|
-
}
|
|
6842
|
+
if (!logSinkInstance) {
|
|
6843
|
+
const formattedMessage = this.formatMessage("info", message, context);
|
|
6844
|
+
process.stderr.write(formattedMessage + "\n");
|
|
6911
6845
|
}
|
|
6846
|
+
this.sendToSink("info", message, context).catch(() => {
|
|
6847
|
+
});
|
|
6912
6848
|
}
|
|
6913
6849
|
}
|
|
6914
|
-
/**
|
|
6915
|
-
* Capitalize phase name for display
|
|
6916
|
-
*/
|
|
6917
|
-
capitalizePhase(phase) {
|
|
6918
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
6919
|
-
}
|
|
6920
6850
|
warn(message, context) {
|
|
6921
6851
|
if (this.shouldLog(LogLevel.WARN)) {
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6852
|
+
if (!logSinkInstance) {
|
|
6853
|
+
const formattedMessage = this.formatMessage("warn", message, context);
|
|
6854
|
+
process.stderr.write(formattedMessage + "\n");
|
|
6855
|
+
}
|
|
6856
|
+
this.sendToSink("warning", message, context).catch(() => {
|
|
6925
6857
|
});
|
|
6926
6858
|
}
|
|
6927
6859
|
}
|
|
6928
6860
|
error(message, error, context) {
|
|
6929
6861
|
if (this.shouldLog(LogLevel.ERROR)) {
|
|
6930
6862
|
const errorContext = error ? { ...context, error: error.message, stack: error.stack } : context;
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6863
|
+
if (!logSinkInstance) {
|
|
6864
|
+
const formattedMessage = this.formatMessage("error", message, errorContext);
|
|
6865
|
+
process.stderr.write(formattedMessage + "\n");
|
|
6866
|
+
}
|
|
6867
|
+
this.sendToSink("error", message, errorContext).catch(() => {
|
|
6934
6868
|
});
|
|
6935
6869
|
}
|
|
6936
6870
|
}
|
|
@@ -6941,7 +6875,7 @@ var Logger = class _Logger {
|
|
|
6941
6875
|
function createLogger(component, logLevel) {
|
|
6942
6876
|
return new Logger(component, logLevel);
|
|
6943
6877
|
}
|
|
6944
|
-
var logger = createLogger("
|
|
6878
|
+
var logger = createLogger("workflows-core");
|
|
6945
6879
|
var logger2 = createLogger("StateMachineLoader");
|
|
6946
6880
|
var StateMachineLoader = class {
|
|
6947
6881
|
stateMachine = null;
|
|
@@ -7165,6 +7099,35 @@ ${continueTransition.additional_instructions}`;
|
|
|
7165
7099
|
}
|
|
7166
7100
|
return stateDefinition.default_instructions;
|
|
7167
7101
|
}
|
|
7102
|
+
/**
|
|
7103
|
+
* Get allowed file patterns for a specific phase.
|
|
7104
|
+
* Returns undefined if no restrictions are defined (all files allowed).
|
|
7105
|
+
*
|
|
7106
|
+
* @param phase - The phase/state name to get patterns for
|
|
7107
|
+
* @returns Array of glob patterns or undefined if all files are allowed
|
|
7108
|
+
*/
|
|
7109
|
+
getAllowedFilePatterns(phase) {
|
|
7110
|
+
if (!this.stateMachine) {
|
|
7111
|
+
throw new Error("State machine not loaded");
|
|
7112
|
+
}
|
|
7113
|
+
const stateDefinition = this.stateMachine.states[phase];
|
|
7114
|
+
if (!stateDefinition) {
|
|
7115
|
+
logger2.error("Unknown phase", new Error(`Unknown phase: ${phase}`));
|
|
7116
|
+
throw new Error(`Unknown phase: ${phase}`);
|
|
7117
|
+
}
|
|
7118
|
+
return stateDefinition.allowed_file_patterns;
|
|
7119
|
+
}
|
|
7120
|
+
/**
|
|
7121
|
+
* Whether the given phase restricts which files may be edited.
|
|
7122
|
+
* Returns false when no allowed_file_patterns are defined (all files allowed).
|
|
7123
|
+
* Callers should use getAllowedFilePatterns + a glob library for actual path matching.
|
|
7124
|
+
*
|
|
7125
|
+
* @param phase - The phase/state name
|
|
7126
|
+
*/
|
|
7127
|
+
hasFileRestrictions(phase) {
|
|
7128
|
+
const patterns = this.getAllowedFilePatterns(phase);
|
|
7129
|
+
return patterns !== void 0 && patterns.length > 0;
|
|
7130
|
+
}
|
|
7168
7131
|
};
|
|
7169
7132
|
var logger3 = createLogger("ConfigManager");
|
|
7170
7133
|
var ConfigManager = class {
|
|
@@ -7234,13 +7197,21 @@ var WorkflowManager = class _WorkflowManager {
|
|
|
7234
7197
|
}
|
|
7235
7198
|
/**
|
|
7236
7199
|
* Parse enabled domains from environment variable
|
|
7200
|
+
* Supports both WORKFLOW_DOMAINS and VIBE_WORKFLOW_DOMAINS (legacy)
|
|
7201
|
+
* WORKFLOW_DOMAINS takes precedence if both are set (modern, non-prefixed version preferred)
|
|
7237
7202
|
*/
|
|
7238
7203
|
parseEnabledDomains() {
|
|
7239
|
-
const domainsEnv = process.env["VIBE_WORKFLOW_DOMAINS"];
|
|
7204
|
+
const domainsEnv = process.env["WORKFLOW_DOMAINS"] || process.env["VIBE_WORKFLOW_DOMAINS"];
|
|
7240
7205
|
if (!domainsEnv) {
|
|
7206
|
+
logger4.debug("No domain configuration found, using default: code");
|
|
7241
7207
|
return /* @__PURE__ */ new Set(["code"]);
|
|
7242
7208
|
}
|
|
7243
|
-
|
|
7209
|
+
const domains = new Set(domainsEnv.split(",").map((d) => d.trim()).filter((d) => d));
|
|
7210
|
+
logger4.debug("Parsed enabled domains", {
|
|
7211
|
+
source: process.env["WORKFLOW_DOMAINS"] ? "WORKFLOW_DOMAINS" : "VIBE_WORKFLOW_DOMAINS",
|
|
7212
|
+
domains: Array.from(domains)
|
|
7213
|
+
});
|
|
7214
|
+
return domains;
|
|
7244
7215
|
}
|
|
7245
7216
|
/**
|
|
7246
7217
|
* Load project-specific workflows from .vibe/workflows/
|
|
@@ -7612,15 +7583,18 @@ var WorkflowManager = class _WorkflowManager {
|
|
|
7612
7583
|
return false;
|
|
7613
7584
|
}
|
|
7614
7585
|
};
|
|
7615
|
-
|
|
7586
|
+
function capitalizePhase(phase) {
|
|
7587
|
+
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
7588
|
+
}
|
|
7589
|
+
var defaultLogger = createLogger("TransitionEngine");
|
|
7616
7590
|
var TransitionEngine = class {
|
|
7617
|
-
stateMachineLoader;
|
|
7618
7591
|
workflowManager;
|
|
7592
|
+
logger;
|
|
7619
7593
|
conversationManager;
|
|
7620
|
-
constructor(projectPath) {
|
|
7621
|
-
this.stateMachineLoader = new StateMachineLoader();
|
|
7594
|
+
constructor(projectPath, logger24 = defaultLogger) {
|
|
7622
7595
|
this.workflowManager = new WorkflowManager();
|
|
7623
|
-
|
|
7596
|
+
this.logger = logger24;
|
|
7597
|
+
this.logger.info("TransitionEngine initialized", { projectPath });
|
|
7624
7598
|
}
|
|
7625
7599
|
/**
|
|
7626
7600
|
* Set the conversation manager (dependency injection)
|
|
@@ -7639,11 +7613,11 @@ var TransitionEngine = class {
|
|
|
7639
7613
|
*/
|
|
7640
7614
|
async isFirstCallFromInitialState(context) {
|
|
7641
7615
|
if (!this.conversationManager) {
|
|
7642
|
-
|
|
7616
|
+
this.logger.warn("ConversationManager not set, assuming first call");
|
|
7643
7617
|
return true;
|
|
7644
7618
|
}
|
|
7645
7619
|
const hasInteractions = await this.conversationManager.hasInteractions(context.conversationId);
|
|
7646
|
-
|
|
7620
|
+
this.logger.debug("Checking first call from initial state", {
|
|
7647
7621
|
hasInteractions,
|
|
7648
7622
|
conversationId: context.conversationId,
|
|
7649
7623
|
currentPhase: context.currentPhase
|
|
@@ -7653,51 +7627,18 @@ var TransitionEngine = class {
|
|
|
7653
7627
|
/**
|
|
7654
7628
|
* Generate instructions for defining phase entrance criteria
|
|
7655
7629
|
*/
|
|
7656
|
-
|
|
7657
|
-
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
7658
|
-
const workflowName = conversationState?.workflowName;
|
|
7659
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
7630
|
+
generateCriteriaDefinitionInstructions(stateMachine) {
|
|
7660
7631
|
const phases = Object.keys(stateMachine.states);
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
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.
|
|
7664
|
-
|
|
7665
|
-
Please update the plan file with a "Phase Entrance Criteria" section that defines specific, measurable criteria for entering each phase:
|
|
7666
|
-
|
|
7667
|
-
## Phase Entrance Criteria
|
|
7668
|
-
|
|
7669
|
-
`;
|
|
7670
|
-
for (const phase of phases) {
|
|
7671
|
-
if (phase === stateMachine.initial_state)
|
|
7672
|
-
continue;
|
|
7673
|
-
const phaseDefinition = stateMachine.states[phase];
|
|
7674
|
-
const capitalizedPhase = this.capitalizePhase(phase);
|
|
7675
|
-
instructions += `### ${capitalizedPhase} Phase
|
|
7676
|
-
*${phaseDefinition.description}*
|
|
7677
|
-
|
|
7678
|
-
**Enter when:**
|
|
7679
|
-
- [ ] [Define specific criteria for entering ${phase} phase]
|
|
7680
|
-
- [ ] [Add measurable conditions that must be met]
|
|
7681
|
-
- [ ] [Include any deliverables or milestones required]
|
|
7682
|
-
|
|
7683
|
-
`;
|
|
7684
|
-
}
|
|
7685
|
-
instructions += `
|
|
7686
|
-
Once you've defined these criteria, we can begin development. Throughout the process, consult these criteria when considering phase transitions.
|
|
7687
|
-
|
|
7688
|
-
**Remember**: These criteria should be specific and measurable so we can clearly determine when each phase is ready to begin.`;
|
|
7689
|
-
return instructions;
|
|
7632
|
+
const phaseList = phases.filter((phase) => phase !== stateMachine.initial_state).map((phase) => capitalizePhase(phase)).join(", ");
|
|
7633
|
+
return `Define entrance criteria for each phase (${phaseList}) in the plan file. Criteria should be specific and measurable.`;
|
|
7690
7634
|
}
|
|
7691
7635
|
/**
|
|
7692
7636
|
* Get phase-specific instructions for continuing work in current phase
|
|
7693
7637
|
*/
|
|
7694
|
-
|
|
7695
|
-
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
7696
|
-
const workflowName = conversationState?.workflowName;
|
|
7697
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
7638
|
+
getContinuePhaseInstructions(phase, stateMachine) {
|
|
7698
7639
|
const stateDefinition = stateMachine.states[phase];
|
|
7699
7640
|
if (!stateDefinition) {
|
|
7700
|
-
|
|
7641
|
+
this.logger.error("Unknown phase", new Error(`Unknown phase: ${phase}`));
|
|
7701
7642
|
throw new Error(`Unknown phase: ${phase}`);
|
|
7702
7643
|
}
|
|
7703
7644
|
const continueTransition = stateDefinition.transitions.find((t) => t.to === phase);
|
|
@@ -7720,19 +7661,17 @@ ${continueTransition.additional_instructions}`;
|
|
|
7720
7661
|
/**
|
|
7721
7662
|
* Get the first development phase from the state machine
|
|
7722
7663
|
*/
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
const workflowName = conversationState?.workflowName;
|
|
7726
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
7727
|
-
const initialState = stateMachine.initial_state;
|
|
7728
|
-
return initialState;
|
|
7664
|
+
getFirstDevelopmentPhase(stateMachine) {
|
|
7665
|
+
return stateMachine.initial_state;
|
|
7729
7666
|
}
|
|
7730
7667
|
/**
|
|
7731
7668
|
* Analyze context and determine appropriate phase transition
|
|
7732
7669
|
*/
|
|
7733
7670
|
async analyzePhaseTransition(context) {
|
|
7734
7671
|
const { currentPhase, projectPath, conversationId, userInput, context: additionalContext, conversationSummary } = context;
|
|
7735
|
-
|
|
7672
|
+
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
7673
|
+
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, conversationState?.workflowName);
|
|
7674
|
+
this.logger.debug("Analyzing phase transition", {
|
|
7736
7675
|
currentPhase,
|
|
7737
7676
|
projectPath,
|
|
7738
7677
|
hasUserInput: !!userInput,
|
|
@@ -7741,14 +7680,14 @@ ${continueTransition.additional_instructions}`;
|
|
|
7741
7680
|
userInput: userInput ? userInput.substring(0, 50) + (userInput.length > 50 ? "..." : "") : void 0
|
|
7742
7681
|
});
|
|
7743
7682
|
if (await this.isFirstCallFromInitialState(context)) {
|
|
7744
|
-
const firstDevelopmentPhase =
|
|
7745
|
-
|
|
7683
|
+
const firstDevelopmentPhase = this.getFirstDevelopmentPhase(stateMachine);
|
|
7684
|
+
this.logger.info("First call from initial state - transitioning to first development phase with criteria", {
|
|
7746
7685
|
currentPhase,
|
|
7747
7686
|
firstDevelopmentPhase,
|
|
7748
7687
|
projectPath
|
|
7749
7688
|
});
|
|
7750
|
-
const criteriaInstructions =
|
|
7751
|
-
const phaseInstructions =
|
|
7689
|
+
const criteriaInstructions = this.generateCriteriaDefinitionInstructions(stateMachine);
|
|
7690
|
+
const phaseInstructions = this.getContinuePhaseInstructions(firstDevelopmentPhase, stateMachine);
|
|
7752
7691
|
return {
|
|
7753
7692
|
newPhase: firstDevelopmentPhase,
|
|
7754
7693
|
// Transition to first development phase
|
|
@@ -7757,8 +7696,8 @@ ${continueTransition.additional_instructions}`;
|
|
|
7757
7696
|
isModeled: true
|
|
7758
7697
|
};
|
|
7759
7698
|
}
|
|
7760
|
-
const continueInstructions =
|
|
7761
|
-
|
|
7699
|
+
const continueInstructions = this.getContinuePhaseInstructions(currentPhase, stateMachine);
|
|
7700
|
+
this.logger.debug("Continuing in current phase - LLM will evaluate transition criteria", {
|
|
7762
7701
|
currentPhase,
|
|
7763
7702
|
projectPath
|
|
7764
7703
|
});
|
|
@@ -7774,7 +7713,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
7774
7713
|
*/
|
|
7775
7714
|
handleExplicitTransition(currentPhase, targetPhase, projectPath, reason, workflowName) {
|
|
7776
7715
|
const stateMachine = this.getStateMachine(projectPath, workflowName);
|
|
7777
|
-
|
|
7716
|
+
this.logger.debug("Handling explicit phase transition", {
|
|
7778
7717
|
currentPhase,
|
|
7779
7718
|
targetPhase,
|
|
7780
7719
|
projectPath,
|
|
@@ -7785,7 +7724,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
7785
7724
|
if (!stateMachine.states[normalizedTargetPhase]) {
|
|
7786
7725
|
const validPhases = Object.keys(stateMachine.states);
|
|
7787
7726
|
const errorMsg = `Invalid target phase: "${targetPhase}". Valid phases are: ${validPhases.join(", ")}`;
|
|
7788
|
-
|
|
7727
|
+
this.logger.error("Invalid target phase", new Error(errorMsg));
|
|
7789
7728
|
throw new Error(errorMsg);
|
|
7790
7729
|
}
|
|
7791
7730
|
const targetState = stateMachine.states[normalizedTargetPhase];
|
|
@@ -7796,7 +7735,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
7796
7735
|
isModeled: false
|
|
7797
7736
|
// Direct phase transitions are not modeled
|
|
7798
7737
|
};
|
|
7799
|
-
|
|
7738
|
+
this.logger.info("Explicit phase transition processed", {
|
|
7800
7739
|
fromPhase: currentPhase,
|
|
7801
7740
|
toPhase: normalizedTargetPhase,
|
|
7802
7741
|
reason: transitionInfo.transitionReason,
|
|
@@ -7809,12 +7748,6 @@ ${continueTransition.additional_instructions}`;
|
|
|
7809
7748
|
isModeled: transitionInfo.isModeled
|
|
7810
7749
|
};
|
|
7811
7750
|
}
|
|
7812
|
-
/**
|
|
7813
|
-
* Capitalize phase name for display
|
|
7814
|
-
*/
|
|
7815
|
-
capitalizePhase(phase) {
|
|
7816
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
7817
|
-
}
|
|
7818
7751
|
/**
|
|
7819
7752
|
* Filter transitions based on agent role (for crowd workflows)
|
|
7820
7753
|
* Returns transitions applicable to the current agent
|
|
@@ -7826,7 +7759,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
7826
7759
|
return transitions.filter((t) => !t.role || t.role === agentRole);
|
|
7827
7760
|
}
|
|
7828
7761
|
};
|
|
7829
|
-
var
|
|
7762
|
+
var logger5 = createLogger("FileStorage");
|
|
7830
7763
|
var FileStorage = class {
|
|
7831
7764
|
conversationsDir;
|
|
7832
7765
|
basePath;
|
|
@@ -7844,11 +7777,11 @@ var FileStorage = class {
|
|
|
7844
7777
|
async initialize() {
|
|
7845
7778
|
try {
|
|
7846
7779
|
await fs4.mkdir(this.conversationsDir, { recursive: true });
|
|
7847
|
-
|
|
7780
|
+
logger5.debug("FileStorage initialized", {
|
|
7848
7781
|
conversationsDir: this.conversationsDir
|
|
7849
7782
|
});
|
|
7850
7783
|
} catch (error) {
|
|
7851
|
-
|
|
7784
|
+
logger5.error("Failed to initialize FileStorage", error);
|
|
7852
7785
|
throw error;
|
|
7853
7786
|
}
|
|
7854
7787
|
}
|
|
@@ -7898,12 +7831,12 @@ var FileStorage = class {
|
|
|
7898
7831
|
await fs4.mkdir(conversationDir, { recursive: true });
|
|
7899
7832
|
const stateJson = JSON.stringify(state, null, 2);
|
|
7900
7833
|
await this.writeAtomic(stateFilePath, stateJson);
|
|
7901
|
-
|
|
7834
|
+
logger5.debug("Conversation state saved", {
|
|
7902
7835
|
conversationId: state.conversationId,
|
|
7903
7836
|
currentPhase: state.currentPhase
|
|
7904
7837
|
});
|
|
7905
7838
|
} catch (error) {
|
|
7906
|
-
|
|
7839
|
+
logger5.error("Failed to save conversation state", error, {
|
|
7907
7840
|
conversationId: state.conversationId
|
|
7908
7841
|
});
|
|
7909
7842
|
throw error;
|
|
@@ -7923,7 +7856,7 @@ var FileStorage = class {
|
|
|
7923
7856
|
if (error.code === "ENOENT") {
|
|
7924
7857
|
return null;
|
|
7925
7858
|
}
|
|
7926
|
-
|
|
7859
|
+
logger5.warn("Failed to read conversation state, returning null", {
|
|
7927
7860
|
conversationId,
|
|
7928
7861
|
error: error.message
|
|
7929
7862
|
});
|
|
@@ -7955,7 +7888,7 @@ var FileStorage = class {
|
|
|
7955
7888
|
if (error.code === "ENOENT") {
|
|
7956
7889
|
return [];
|
|
7957
7890
|
}
|
|
7958
|
-
|
|
7891
|
+
logger5.error("Failed to get all conversation states", error);
|
|
7959
7892
|
throw error;
|
|
7960
7893
|
}
|
|
7961
7894
|
}
|
|
@@ -7967,13 +7900,13 @@ var FileStorage = class {
|
|
|
7967
7900
|
const conversationDir = this.getConversationDir(conversationId);
|
|
7968
7901
|
try {
|
|
7969
7902
|
await fs4.rm(conversationDir, { recursive: true, force: true });
|
|
7970
|
-
|
|
7903
|
+
logger5.debug("Conversation state deleted", { conversationId });
|
|
7971
7904
|
return true;
|
|
7972
7905
|
} catch (error) {
|
|
7973
7906
|
if (error.code === "ENOENT") {
|
|
7974
7907
|
return false;
|
|
7975
7908
|
}
|
|
7976
|
-
|
|
7909
|
+
logger5.error("Failed to delete conversation state", error, {
|
|
7977
7910
|
conversationId
|
|
7978
7911
|
});
|
|
7979
7912
|
throw error;
|
|
@@ -7990,12 +7923,12 @@ var FileStorage = class {
|
|
|
7990
7923
|
await fs4.mkdir(conversationDir, { recursive: true });
|
|
7991
7924
|
const logLine = JSON.stringify(log) + "\n";
|
|
7992
7925
|
await fs4.appendFile(interactionsFilePath, logLine, "utf-8");
|
|
7993
|
-
|
|
7926
|
+
logger5.debug("Interaction logged", {
|
|
7994
7927
|
conversationId: log.conversationId,
|
|
7995
7928
|
toolName: log.toolName
|
|
7996
7929
|
});
|
|
7997
7930
|
} catch (error) {
|
|
7998
|
-
|
|
7931
|
+
logger5.error("Failed to log interaction", error, {
|
|
7999
7932
|
conversationId: log.conversationId,
|
|
8000
7933
|
toolName: log.toolName
|
|
8001
7934
|
});
|
|
@@ -8017,7 +7950,7 @@ var FileStorage = class {
|
|
|
8017
7950
|
const log = JSON.parse(line);
|
|
8018
7951
|
logs.push(log);
|
|
8019
7952
|
} catch {
|
|
8020
|
-
|
|
7953
|
+
logger5.warn("Skipping corrupted interaction log line", {
|
|
8021
7954
|
conversationId
|
|
8022
7955
|
});
|
|
8023
7956
|
}
|
|
@@ -8027,7 +7960,7 @@ var FileStorage = class {
|
|
|
8027
7960
|
if (error.code === "ENOENT") {
|
|
8028
7961
|
return [];
|
|
8029
7962
|
}
|
|
8030
|
-
|
|
7963
|
+
logger5.error("Failed to get interaction logs", error, {
|
|
8031
7964
|
conversationId
|
|
8032
7965
|
});
|
|
8033
7966
|
throw error;
|
|
@@ -8047,12 +7980,12 @@ var FileStorage = class {
|
|
|
8047
7980
|
const interactionsFilePath = this.getInteractionsFilePath(conversationId);
|
|
8048
7981
|
try {
|
|
8049
7982
|
await fs4.unlink(interactionsFilePath);
|
|
8050
|
-
|
|
7983
|
+
logger5.debug("Interaction logs deleted", { conversationId });
|
|
8051
7984
|
} catch (error) {
|
|
8052
7985
|
if (error.code === "ENOENT") {
|
|
8053
7986
|
return;
|
|
8054
7987
|
}
|
|
8055
|
-
|
|
7988
|
+
logger5.warn("Failed to delete interaction logs", {
|
|
8056
7989
|
conversationId,
|
|
8057
7990
|
error: error.message
|
|
8058
7991
|
});
|
|
@@ -8071,16 +8004,16 @@ var FileStorage = class {
|
|
|
8071
8004
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8072
8005
|
};
|
|
8073
8006
|
await this.saveConversationState(updatedState);
|
|
8074
|
-
|
|
8007
|
+
logger5.debug("Conversation state reset", { conversationId });
|
|
8075
8008
|
}
|
|
8076
8009
|
/**
|
|
8077
8010
|
* Close file storage (no-op for file-based storage)
|
|
8078
8011
|
*/
|
|
8079
8012
|
async close() {
|
|
8080
|
-
|
|
8013
|
+
logger5.debug("FileStorage closed");
|
|
8081
8014
|
}
|
|
8082
8015
|
};
|
|
8083
|
-
var
|
|
8016
|
+
var logger6 = createLogger("PathValidationUtils");
|
|
8084
8017
|
var PathValidationUtils = class {
|
|
8085
8018
|
/**
|
|
8086
8019
|
* Validate if a string is a known template name
|
|
@@ -8108,7 +8041,7 @@ var PathValidationUtils = class {
|
|
|
8108
8041
|
error: "Path points to a directory, not a file"
|
|
8109
8042
|
};
|
|
8110
8043
|
}
|
|
8111
|
-
|
|
8044
|
+
logger6.debug("File path validated successfully", {
|
|
8112
8045
|
originalPath: filePath,
|
|
8113
8046
|
resolvedPath
|
|
8114
8047
|
});
|
|
@@ -8118,7 +8051,7 @@ var PathValidationUtils = class {
|
|
|
8118
8051
|
};
|
|
8119
8052
|
} catch (error) {
|
|
8120
8053
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
8121
|
-
|
|
8054
|
+
logger6.debug("File path validation failed", {
|
|
8122
8055
|
filePath,
|
|
8123
8056
|
error: errorMessage
|
|
8124
8057
|
});
|
|
@@ -8148,7 +8081,7 @@ var PathValidationUtils = class {
|
|
|
8148
8081
|
error: "Path is neither a file nor a directory"
|
|
8149
8082
|
};
|
|
8150
8083
|
}
|
|
8151
|
-
|
|
8084
|
+
logger6.debug("File or directory path validated successfully", {
|
|
8152
8085
|
originalPath: filePath,
|
|
8153
8086
|
resolvedPath,
|
|
8154
8087
|
isFile: stats.isFile(),
|
|
@@ -8160,7 +8093,7 @@ var PathValidationUtils = class {
|
|
|
8160
8093
|
};
|
|
8161
8094
|
} catch (error) {
|
|
8162
8095
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
8163
|
-
|
|
8096
|
+
logger6.debug("File or directory path validation failed", {
|
|
8164
8097
|
filePath,
|
|
8165
8098
|
error: errorMessage
|
|
8166
8099
|
});
|
|
@@ -8270,7 +8203,7 @@ function getPathBasename(filePath, fallback = "unknown") {
|
|
|
8270
8203
|
const result = basename(trimmedPath);
|
|
8271
8204
|
return result || fallback;
|
|
8272
8205
|
}
|
|
8273
|
-
var
|
|
8206
|
+
var logger7 = createLogger("PlanManager");
|
|
8274
8207
|
var PlanManager = class {
|
|
8275
8208
|
stateMachine = null;
|
|
8276
8209
|
/**
|
|
@@ -8278,7 +8211,7 @@ var PlanManager = class {
|
|
|
8278
8211
|
*/
|
|
8279
8212
|
setStateMachine(stateMachine) {
|
|
8280
8213
|
this.stateMachine = stateMachine;
|
|
8281
|
-
|
|
8214
|
+
logger7.debug("State machine set for plan manager", {
|
|
8282
8215
|
name: stateMachine.name,
|
|
8283
8216
|
phases: Object.keys(stateMachine.states)
|
|
8284
8217
|
});
|
|
@@ -8287,7 +8220,7 @@ var PlanManager = class {
|
|
|
8287
8220
|
* Set the task backend configuration
|
|
8288
8221
|
*/
|
|
8289
8222
|
setTaskBackend(taskBackend) {
|
|
8290
|
-
|
|
8223
|
+
logger7.debug("Task backend set for plan manager (markdown mode)", {
|
|
8291
8224
|
backend: taskBackend.backend,
|
|
8292
8225
|
available: taskBackend.isAvailable
|
|
8293
8226
|
});
|
|
@@ -8315,43 +8248,43 @@ var PlanManager = class {
|
|
|
8315
8248
|
* Create initial plan file if it doesn't exist
|
|
8316
8249
|
*/
|
|
8317
8250
|
async ensurePlanFile(planFilePath, projectPath, gitBranch) {
|
|
8318
|
-
|
|
8251
|
+
logger7.debug("Ensuring plan file exists", {
|
|
8319
8252
|
planFilePath,
|
|
8320
8253
|
projectPath,
|
|
8321
8254
|
gitBranch
|
|
8322
8255
|
});
|
|
8323
8256
|
const planInfo = await this.getPlanFileInfo(planFilePath);
|
|
8324
8257
|
if (!planInfo.exists) {
|
|
8325
|
-
|
|
8258
|
+
logger7.info("Plan file not found, creating initial plan", {
|
|
8326
8259
|
planFilePath
|
|
8327
8260
|
});
|
|
8328
8261
|
await this.createInitialPlanFile(planFilePath, projectPath, gitBranch);
|
|
8329
|
-
|
|
8262
|
+
logger7.info("Initial plan file created successfully", { planFilePath });
|
|
8330
8263
|
} else {
|
|
8331
|
-
|
|
8264
|
+
logger7.debug("Plan file already exists", { planFilePath });
|
|
8332
8265
|
}
|
|
8333
8266
|
}
|
|
8334
8267
|
/**
|
|
8335
8268
|
* Create initial plan file with template content
|
|
8336
8269
|
*/
|
|
8337
8270
|
async createInitialPlanFile(planFilePath, projectPath, gitBranch) {
|
|
8338
|
-
|
|
8271
|
+
logger7.debug("Creating initial plan file", { planFilePath });
|
|
8339
8272
|
try {
|
|
8340
8273
|
await mkdir(dirname2(planFilePath), { recursive: true });
|
|
8341
|
-
|
|
8274
|
+
logger7.debug("Plan file directory ensured", {
|
|
8342
8275
|
directory: dirname2(planFilePath)
|
|
8343
8276
|
});
|
|
8344
8277
|
const projectName = getPathBasename(projectPath, "Unknown Project");
|
|
8345
8278
|
const branchInfo = gitBranch !== "no-git" ? ` (${gitBranch} branch)` : "";
|
|
8346
8279
|
const initialContent = this.generateInitialPlanContent(projectName, branchInfo);
|
|
8347
8280
|
await writeFile(planFilePath, initialContent, "utf-8");
|
|
8348
|
-
|
|
8281
|
+
logger7.info("Initial plan file written successfully", {
|
|
8349
8282
|
planFilePath,
|
|
8350
8283
|
contentLength: initialContent.length,
|
|
8351
8284
|
projectName
|
|
8352
8285
|
});
|
|
8353
8286
|
} catch (error) {
|
|
8354
|
-
|
|
8287
|
+
logger7.error("Failed to create initial plan file", error, {
|
|
8355
8288
|
planFilePath
|
|
8356
8289
|
});
|
|
8357
8290
|
throw error;
|
|
@@ -8383,7 +8316,7 @@ var PlanManager = class {
|
|
|
8383
8316
|
*Additional context and observations*
|
|
8384
8317
|
|
|
8385
8318
|
`;
|
|
8386
|
-
content += `## ${
|
|
8319
|
+
content += `## ${capitalizePhase(initialPhase)}
|
|
8387
8320
|
### Tasks
|
|
8388
8321
|
- [ ] *Tasks will be added as they are identified*
|
|
8389
8322
|
|
|
@@ -8393,7 +8326,7 @@ var PlanManager = class {
|
|
|
8393
8326
|
`;
|
|
8394
8327
|
for (const phase of phases) {
|
|
8395
8328
|
if (phase !== initialPhase) {
|
|
8396
|
-
content += `## ${
|
|
8329
|
+
content += `## ${capitalizePhase(phase)}
|
|
8397
8330
|
### Tasks
|
|
8398
8331
|
- [ ] *To be added when this phase becomes active*
|
|
8399
8332
|
|
|
@@ -8445,31 +8378,31 @@ var PlanManager = class {
|
|
|
8445
8378
|
}
|
|
8446
8379
|
const phaseDefinition = this.stateMachine.states[phase];
|
|
8447
8380
|
if (!phaseDefinition) {
|
|
8448
|
-
|
|
8449
|
-
return `Update the ${
|
|
8381
|
+
logger7.warn("Unknown phase for plan file guidance", { phase });
|
|
8382
|
+
return `Update the ${capitalizePhase(phase)} section with current progress and mark completed tasks.`;
|
|
8450
8383
|
}
|
|
8451
|
-
const capitalizedPhase =
|
|
8384
|
+
const capitalizedPhase = capitalizePhase(phase);
|
|
8452
8385
|
return `Update the ${capitalizedPhase} section with progress. Mark completed tasks with [x] and add new tasks as they are identified.`;
|
|
8453
8386
|
}
|
|
8454
8387
|
/**
|
|
8455
8388
|
* Delete plan file
|
|
8456
8389
|
*/
|
|
8457
8390
|
async deletePlanFile(planFilePath) {
|
|
8458
|
-
|
|
8391
|
+
logger7.debug("Deleting plan file", { planFilePath });
|
|
8459
8392
|
try {
|
|
8460
8393
|
await access2(planFilePath);
|
|
8461
8394
|
const { unlink: unlink2 } = await import("fs/promises");
|
|
8462
8395
|
await unlink2(planFilePath);
|
|
8463
|
-
|
|
8396
|
+
logger7.info("Plan file deleted successfully", { planFilePath });
|
|
8464
8397
|
return true;
|
|
8465
8398
|
} catch (error) {
|
|
8466
8399
|
if (error.code === "ENOENT") {
|
|
8467
|
-
|
|
8400
|
+
logger7.debug("Plan file does not exist, nothing to delete", {
|
|
8468
8401
|
planFilePath
|
|
8469
8402
|
});
|
|
8470
8403
|
return true;
|
|
8471
8404
|
}
|
|
8472
|
-
|
|
8405
|
+
logger7.error("Failed to delete plan file", error, {
|
|
8473
8406
|
planFilePath
|
|
8474
8407
|
});
|
|
8475
8408
|
throw error;
|
|
@@ -8479,32 +8412,26 @@ var PlanManager = class {
|
|
|
8479
8412
|
* Ensure plan file is deleted (verify deletion)
|
|
8480
8413
|
*/
|
|
8481
8414
|
async ensurePlanFileDeleted(planFilePath) {
|
|
8482
|
-
|
|
8415
|
+
logger7.debug("Ensuring plan file is deleted", { planFilePath });
|
|
8483
8416
|
try {
|
|
8484
8417
|
await access2(planFilePath);
|
|
8485
|
-
|
|
8418
|
+
logger7.warn("Plan file still exists after deletion attempt", {
|
|
8486
8419
|
planFilePath
|
|
8487
8420
|
});
|
|
8488
8421
|
return false;
|
|
8489
8422
|
} catch (error) {
|
|
8490
8423
|
if (error.code === "ENOENT") {
|
|
8491
|
-
|
|
8424
|
+
logger7.debug("Plan file successfully deleted (does not exist)", {
|
|
8492
8425
|
planFilePath
|
|
8493
8426
|
});
|
|
8494
8427
|
return true;
|
|
8495
8428
|
}
|
|
8496
|
-
|
|
8429
|
+
logger7.error("Error checking plan file deletion", error, {
|
|
8497
8430
|
planFilePath
|
|
8498
8431
|
});
|
|
8499
8432
|
throw error;
|
|
8500
8433
|
}
|
|
8501
8434
|
}
|
|
8502
|
-
/**
|
|
8503
|
-
* Capitalize phase name for display
|
|
8504
|
-
*/
|
|
8505
|
-
capitalizePhase(phase) {
|
|
8506
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
8507
|
-
}
|
|
8508
8435
|
/**
|
|
8509
8436
|
* Generate workflow documentation URL for predefined workflows
|
|
8510
8437
|
* Returns undefined for custom workflows
|
|
@@ -8515,8 +8442,22 @@ var PlanManager = class {
|
|
|
8515
8442
|
}
|
|
8516
8443
|
return `https://mrsimpson.github.io/responsible-vibe-mcp/workflows/${workflowName}`;
|
|
8517
8444
|
}
|
|
8445
|
+
/**
|
|
8446
|
+
* Generate base instructions for the LLM after a workflow is started.
|
|
8447
|
+
* Instructs the LLM to populate the Goal section and define phase entrance
|
|
8448
|
+
* criteria in the freshly created plan file.
|
|
8449
|
+
*/
|
|
8450
|
+
getInitialPlanGuidance(planFilePath, workflowDocUrl) {
|
|
8451
|
+
const docInfo = workflowDocUrl ? `
|
|
8452
|
+
|
|
8453
|
+
Inform the user about the chosen workflow. They can visit: ${workflowDocUrl} to get detailed information.` : "";
|
|
8454
|
+
const i18nNote = `
|
|
8455
|
+
|
|
8456
|
+
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.`;
|
|
8457
|
+
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}`;
|
|
8458
|
+
}
|
|
8518
8459
|
};
|
|
8519
|
-
var
|
|
8460
|
+
var logger8 = createLogger("ConversationManager");
|
|
8520
8461
|
var ConversationManager = class {
|
|
8521
8462
|
database;
|
|
8522
8463
|
projectPath;
|
|
@@ -8543,11 +8484,11 @@ var ConversationManager = class {
|
|
|
8543
8484
|
async getConversationContext() {
|
|
8544
8485
|
const projectPath = this.getProjectPath();
|
|
8545
8486
|
const gitBranch = this.getGitBranch(projectPath);
|
|
8546
|
-
|
|
8487
|
+
logger8.debug("Getting conversation context", { projectPath, gitBranch });
|
|
8547
8488
|
const conversationId = this.generateConversationId(projectPath, gitBranch);
|
|
8548
8489
|
const state = await this.database.getConversationState(conversationId);
|
|
8549
8490
|
if (!state) {
|
|
8550
|
-
|
|
8491
|
+
logger8.warn("No conversation found for context", {
|
|
8551
8492
|
projectPath,
|
|
8552
8493
|
gitBranch,
|
|
8553
8494
|
conversationId
|
|
@@ -8576,7 +8517,7 @@ var ConversationManager = class {
|
|
|
8576
8517
|
async createConversationContext(workflowName, projectPathOverride) {
|
|
8577
8518
|
const projectPath = projectPathOverride || this.getProjectPath();
|
|
8578
8519
|
const gitBranch = this.getGitBranch(projectPath);
|
|
8579
|
-
|
|
8520
|
+
logger8.debug("Creating conversation context", {
|
|
8580
8521
|
projectPath,
|
|
8581
8522
|
gitBranch,
|
|
8582
8523
|
workflowName
|
|
@@ -8586,14 +8527,14 @@ var ConversationManager = class {
|
|
|
8586
8527
|
if (existingState) {
|
|
8587
8528
|
if (existingState.workflowName !== workflowName) {
|
|
8588
8529
|
const errorMessage = `Development conversation already exists with workflow '${existingState.workflowName}'. Cannot change to '${workflowName}'. Use reset_development() first to start with a new workflow.`;
|
|
8589
|
-
|
|
8530
|
+
logger8.error("Attempted workflow change on existing conversation", new Error(errorMessage), {
|
|
8590
8531
|
existingWorkflow: existingState.workflowName,
|
|
8591
8532
|
requestedWorkflow: workflowName,
|
|
8592
8533
|
conversationId
|
|
8593
8534
|
});
|
|
8594
8535
|
throw new Error(errorMessage);
|
|
8595
8536
|
}
|
|
8596
|
-
|
|
8537
|
+
logger8.debug("Conversation already exists, returning existing context", {
|
|
8597
8538
|
conversationId
|
|
8598
8539
|
});
|
|
8599
8540
|
return {
|
|
@@ -8622,7 +8563,7 @@ var ConversationManager = class {
|
|
|
8622
8563
|
* @param updates - Partial state updates to apply
|
|
8623
8564
|
*/
|
|
8624
8565
|
async updateConversationState(conversationId, updates) {
|
|
8625
|
-
|
|
8566
|
+
logger8.debug("Updating conversation state", { conversationId, updates });
|
|
8626
8567
|
const currentState = await this.database.getConversationState(conversationId);
|
|
8627
8568
|
if (!currentState) {
|
|
8628
8569
|
throw new Error(`Conversation state not found for ID: ${conversationId}`);
|
|
@@ -8633,7 +8574,7 @@ var ConversationManager = class {
|
|
|
8633
8574
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8634
8575
|
};
|
|
8635
8576
|
await this.database.saveConversationState(updatedState);
|
|
8636
|
-
|
|
8577
|
+
logger8.info("Conversation state updated", {
|
|
8637
8578
|
conversationId,
|
|
8638
8579
|
currentPhase: updatedState.currentPhase
|
|
8639
8580
|
});
|
|
@@ -8646,7 +8587,7 @@ var ConversationManager = class {
|
|
|
8646
8587
|
* @param gitBranch - Git branch name
|
|
8647
8588
|
*/
|
|
8648
8589
|
async createNewConversationState(conversationId, projectPath, gitBranch, workflowName = "waterfall") {
|
|
8649
|
-
|
|
8590
|
+
logger8.info("Creating new conversation state", {
|
|
8650
8591
|
conversationId,
|
|
8651
8592
|
projectPath,
|
|
8652
8593
|
gitBranch
|
|
@@ -8670,7 +8611,7 @@ var ConversationManager = class {
|
|
|
8670
8611
|
updatedAt: timestamp2
|
|
8671
8612
|
};
|
|
8672
8613
|
await this.database.saveConversationState(newState);
|
|
8673
|
-
|
|
8614
|
+
logger8.info("New conversation state created", {
|
|
8674
8615
|
conversationId,
|
|
8675
8616
|
planFilePath,
|
|
8676
8617
|
initialPhase
|
|
@@ -8713,7 +8654,7 @@ var ConversationManager = class {
|
|
|
8713
8654
|
getGitBranch(projectPath) {
|
|
8714
8655
|
try {
|
|
8715
8656
|
if (!existsSync(`${projectPath}/.git`)) {
|
|
8716
|
-
|
|
8657
|
+
logger8.debug('Not a git repository, using "default" as branch name', {
|
|
8717
8658
|
projectPath
|
|
8718
8659
|
});
|
|
8719
8660
|
return "default";
|
|
@@ -8724,10 +8665,10 @@ var ConversationManager = class {
|
|
|
8724
8665
|
stdio: ["ignore", "pipe", "ignore"]
|
|
8725
8666
|
// Suppress stderr
|
|
8726
8667
|
}).trim();
|
|
8727
|
-
|
|
8668
|
+
logger8.debug("Detected git branch", { projectPath, branch });
|
|
8728
8669
|
return branch;
|
|
8729
8670
|
} catch (_error) {
|
|
8730
|
-
|
|
8671
|
+
logger8.debug('Failed to get git branch, using "default" as branch name', {
|
|
8731
8672
|
projectPath
|
|
8732
8673
|
});
|
|
8733
8674
|
return "default";
|
|
@@ -8741,13 +8682,13 @@ var ConversationManager = class {
|
|
|
8741
8682
|
try {
|
|
8742
8683
|
const interactions = await this.database.getInteractionsByConversationId(conversationId);
|
|
8743
8684
|
const count = interactions.length;
|
|
8744
|
-
|
|
8685
|
+
logger8.debug("Checked interaction count for conversation", {
|
|
8745
8686
|
conversationId,
|
|
8746
8687
|
count
|
|
8747
8688
|
});
|
|
8748
8689
|
return count > 0;
|
|
8749
8690
|
} catch (error) {
|
|
8750
|
-
|
|
8691
|
+
logger8.error("Failed to check interaction count", error, {
|
|
8751
8692
|
conversationId
|
|
8752
8693
|
});
|
|
8753
8694
|
return false;
|
|
@@ -8757,24 +8698,24 @@ var ConversationManager = class {
|
|
|
8757
8698
|
* Reset conversation data (hybrid approach)
|
|
8758
8699
|
*/
|
|
8759
8700
|
async resetConversation(confirm, reason) {
|
|
8760
|
-
|
|
8701
|
+
logger8.info("Starting conversation reset", { confirm, reason });
|
|
8761
8702
|
this.validateResetRequest(confirm);
|
|
8762
8703
|
const context = await this.getConversationContext();
|
|
8763
8704
|
const resetItems = [];
|
|
8764
8705
|
try {
|
|
8765
8706
|
await this.database.softDeleteInteractionLogs(context.conversationId);
|
|
8766
8707
|
resetItems.push("interaction_logs");
|
|
8767
|
-
|
|
8708
|
+
logger8.debug("Interaction logs soft deleted");
|
|
8768
8709
|
await this.database.deleteConversationState(context.conversationId);
|
|
8769
8710
|
resetItems.push("conversation_state");
|
|
8770
|
-
|
|
8711
|
+
logger8.debug("Conversation state hard deleted");
|
|
8771
8712
|
const planManager = new PlanManager();
|
|
8772
8713
|
await planManager.deletePlanFile(context.planFilePath);
|
|
8773
8714
|
resetItems.push("plan_file");
|
|
8774
|
-
|
|
8715
|
+
logger8.debug("Plan file deleted");
|
|
8775
8716
|
await this.verifyResetCleanup(context.conversationId, context.planFilePath);
|
|
8776
8717
|
const message = `Successfully reset conversation ${context.conversationId}. Reset items: ${resetItems.join(", ")}${reason ? `. Reason: ${reason}` : ""}`;
|
|
8777
|
-
|
|
8718
|
+
logger8.info("Conversation reset completed successfully", {
|
|
8778
8719
|
conversationId: context.conversationId,
|
|
8779
8720
|
resetItems,
|
|
8780
8721
|
reason
|
|
@@ -8786,7 +8727,7 @@ var ConversationManager = class {
|
|
|
8786
8727
|
message
|
|
8787
8728
|
};
|
|
8788
8729
|
} catch (error) {
|
|
8789
|
-
|
|
8730
|
+
logger8.error("Failed to reset conversation", error, {
|
|
8790
8731
|
conversationId: context.conversationId,
|
|
8791
8732
|
resetItems,
|
|
8792
8733
|
reason
|
|
@@ -8806,7 +8747,7 @@ var ConversationManager = class {
|
|
|
8806
8747
|
* Verify that reset cleanup was successful
|
|
8807
8748
|
*/
|
|
8808
8749
|
async verifyResetCleanup(conversationId, planFilePath) {
|
|
8809
|
-
|
|
8750
|
+
logger8.debug("Verifying reset cleanup", { conversationId, planFilePath });
|
|
8810
8751
|
try {
|
|
8811
8752
|
const state = await this.database.getConversationState(conversationId);
|
|
8812
8753
|
if (state) {
|
|
@@ -8817,9 +8758,9 @@ var ConversationManager = class {
|
|
|
8817
8758
|
if (!isDeleted) {
|
|
8818
8759
|
throw new Error("Plan file was not properly deleted");
|
|
8819
8760
|
}
|
|
8820
|
-
|
|
8761
|
+
logger8.debug("Reset cleanup verification successful");
|
|
8821
8762
|
} catch (error) {
|
|
8822
|
-
|
|
8763
|
+
logger8.error("Reset cleanup verification failed", error);
|
|
8823
8764
|
throw error;
|
|
8824
8765
|
}
|
|
8825
8766
|
}
|
|
@@ -8827,20 +8768,20 @@ var ConversationManager = class {
|
|
|
8827
8768
|
* Clean up conversation data (used internally)
|
|
8828
8769
|
*/
|
|
8829
8770
|
async cleanupConversationData(conversationId) {
|
|
8830
|
-
|
|
8771
|
+
logger8.debug("Cleaning up conversation data", { conversationId });
|
|
8831
8772
|
try {
|
|
8832
8773
|
await this.database.softDeleteInteractionLogs(conversationId);
|
|
8833
8774
|
await this.database.deleteConversationState(conversationId);
|
|
8834
|
-
|
|
8775
|
+
logger8.debug("Conversation data cleanup completed", { conversationId });
|
|
8835
8776
|
} catch (error) {
|
|
8836
|
-
|
|
8777
|
+
logger8.error("Failed to cleanup conversation data", error, {
|
|
8837
8778
|
conversationId
|
|
8838
8779
|
});
|
|
8839
8780
|
throw error;
|
|
8840
8781
|
}
|
|
8841
8782
|
}
|
|
8842
8783
|
};
|
|
8843
|
-
var
|
|
8784
|
+
var logger9 = createLogger("TemplateManager");
|
|
8844
8785
|
var TemplateManager = class {
|
|
8845
8786
|
templatesPath;
|
|
8846
8787
|
constructor() {
|
|
@@ -8869,13 +8810,13 @@ var TemplateManager = class {
|
|
|
8869
8810
|
for (const strategy of strategies) {
|
|
8870
8811
|
try {
|
|
8871
8812
|
__require2("fs").accessSync(strategy);
|
|
8872
|
-
|
|
8813
|
+
logger9.debug("Using templates path", { path: strategy });
|
|
8873
8814
|
return strategy;
|
|
8874
8815
|
} catch (_error) {
|
|
8875
8816
|
}
|
|
8876
8817
|
}
|
|
8877
8818
|
const fallback = strategies[0];
|
|
8878
|
-
|
|
8819
|
+
logger9.warn("No templates directory found, using fallback", {
|
|
8879
8820
|
fallback,
|
|
8880
8821
|
strategies
|
|
8881
8822
|
});
|
|
@@ -8929,7 +8870,7 @@ var TemplateManager = class {
|
|
|
8929
8870
|
const content = await readFile2(templateFilePath, "utf-8");
|
|
8930
8871
|
return { content };
|
|
8931
8872
|
} catch (error) {
|
|
8932
|
-
|
|
8873
|
+
logger9.error(`Failed to load template: ${type2}/${template}`, error);
|
|
8933
8874
|
throw new Error(`Template not found: ${type2}/${template}. Tried: ${templatePath} (directory) and ${templateFilePath} (file)`);
|
|
8934
8875
|
}
|
|
8935
8876
|
}
|
|
@@ -9010,26 +8951,28 @@ var TemplateManager = class {
|
|
|
9010
8951
|
}
|
|
9011
8952
|
templates.sort();
|
|
9012
8953
|
} catch (error) {
|
|
9013
|
-
|
|
8954
|
+
logger9.warn(`Failed to scan templates for type: ${type2}`, {
|
|
9014
8955
|
typePath,
|
|
9015
8956
|
error: error instanceof Error ? error.message : String(error)
|
|
9016
8957
|
});
|
|
9017
8958
|
}
|
|
9018
8959
|
}
|
|
9019
|
-
|
|
8960
|
+
logger9.debug("Discovered available templates", result);
|
|
9020
8961
|
return result;
|
|
9021
8962
|
} catch (error) {
|
|
9022
|
-
|
|
8963
|
+
logger9.error("Failed to discover templates", error);
|
|
9023
8964
|
return result;
|
|
9024
8965
|
}
|
|
9025
8966
|
}
|
|
9026
8967
|
};
|
|
9027
|
-
var
|
|
8968
|
+
var defaultLogger2 = createLogger("ProjectDocsManager");
|
|
9028
8969
|
var ProjectDocsManager = class {
|
|
9029
8970
|
templateManager;
|
|
9030
8971
|
// Make public for access from other classes
|
|
9031
|
-
|
|
8972
|
+
logger;
|
|
8973
|
+
constructor(logger24 = defaultLogger2) {
|
|
9032
8974
|
this.templateManager = new TemplateManager();
|
|
8975
|
+
this.logger = logger24;
|
|
9033
8976
|
}
|
|
9034
8977
|
/**
|
|
9035
8978
|
* Get project docs directory path
|
|
@@ -9200,7 +9143,7 @@ var ProjectDocsManager = class {
|
|
|
9200
9143
|
} else {
|
|
9201
9144
|
skipped.push("design.md");
|
|
9202
9145
|
}
|
|
9203
|
-
|
|
9146
|
+
this.logger.info("Project docs creation/linking completed", {
|
|
9204
9147
|
created,
|
|
9205
9148
|
linked,
|
|
9206
9149
|
skipped,
|
|
@@ -9219,13 +9162,13 @@ var ProjectDocsManager = class {
|
|
|
9219
9162
|
const targetDir = dirname4(targetPath);
|
|
9220
9163
|
const relativePath = relative(targetDir, sourcePath);
|
|
9221
9164
|
await symlink(relativePath, targetPath);
|
|
9222
|
-
|
|
9165
|
+
this.logger.debug("Symlink created successfully", {
|
|
9223
9166
|
sourcePath,
|
|
9224
9167
|
targetPath,
|
|
9225
9168
|
relativePath
|
|
9226
9169
|
});
|
|
9227
9170
|
} catch (error) {
|
|
9228
|
-
|
|
9171
|
+
this.logger.error("Failed to create symlink", error, {
|
|
9229
9172
|
sourcePath,
|
|
9230
9173
|
targetPath
|
|
9231
9174
|
});
|
|
@@ -9239,14 +9182,14 @@ var ProjectDocsManager = class {
|
|
|
9239
9182
|
try {
|
|
9240
9183
|
const stats = await lstat(documentPath);
|
|
9241
9184
|
await unlink(documentPath);
|
|
9242
|
-
|
|
9185
|
+
this.logger.debug("Existing document removed", {
|
|
9243
9186
|
documentPath,
|
|
9244
9187
|
wasSymlink: stats.isSymbolicLink()
|
|
9245
9188
|
});
|
|
9246
9189
|
} catch (error) {
|
|
9247
9190
|
const nodeError = error;
|
|
9248
9191
|
if (error instanceof Error && "code" in nodeError && nodeError.code !== "ENOENT") {
|
|
9249
|
-
|
|
9192
|
+
this.logger.debug("Failed to remove existing document", {
|
|
9250
9193
|
documentPath,
|
|
9251
9194
|
error: nodeError.message
|
|
9252
9195
|
});
|
|
@@ -9268,9 +9211,9 @@ var ProjectDocsManager = class {
|
|
|
9268
9211
|
await writeFile2(filePath, file.content.toString());
|
|
9269
9212
|
}
|
|
9270
9213
|
}
|
|
9271
|
-
|
|
9214
|
+
this.logger.debug(`Created ${type2} document`, { documentPath, template });
|
|
9272
9215
|
} catch (error) {
|
|
9273
|
-
|
|
9216
|
+
this.logger.error(`Failed to create ${type2} document`, error, {
|
|
9274
9217
|
documentPath,
|
|
9275
9218
|
template
|
|
9276
9219
|
});
|
|
@@ -9337,8 +9280,8 @@ var ProjectDocsManager = class {
|
|
|
9337
9280
|
}
|
|
9338
9281
|
}
|
|
9339
9282
|
};
|
|
9340
|
-
var
|
|
9341
|
-
var
|
|
9283
|
+
var logger10 = createLogger("FileDetectionManager");
|
|
9284
|
+
var logger11 = createLogger("GitManager");
|
|
9342
9285
|
var GitManager = class {
|
|
9343
9286
|
/**
|
|
9344
9287
|
* Check if a directory is a git repository
|
|
@@ -9352,7 +9295,7 @@ var GitManager = class {
|
|
|
9352
9295
|
static getCurrentBranch(projectPath) {
|
|
9353
9296
|
try {
|
|
9354
9297
|
if (!this.isGitRepository(projectPath)) {
|
|
9355
|
-
|
|
9298
|
+
logger11.debug('Not a git repository, using "default" as branch name', {
|
|
9356
9299
|
projectPath
|
|
9357
9300
|
});
|
|
9358
9301
|
return "default";
|
|
@@ -9362,10 +9305,10 @@ var GitManager = class {
|
|
|
9362
9305
|
encoding: "utf-8",
|
|
9363
9306
|
stdio: ["ignore", "pipe", "ignore"]
|
|
9364
9307
|
}).trim();
|
|
9365
|
-
|
|
9308
|
+
logger11.debug("Detected git branch", { projectPath, branch });
|
|
9366
9309
|
return branch;
|
|
9367
9310
|
} catch (_error) {
|
|
9368
|
-
|
|
9311
|
+
logger11.debug('Failed to get git branch, using "default" as branch name', {
|
|
9369
9312
|
projectPath
|
|
9370
9313
|
});
|
|
9371
9314
|
return "default";
|
|
@@ -9386,7 +9329,7 @@ var GitManager = class {
|
|
|
9386
9329
|
}).trim();
|
|
9387
9330
|
return hash;
|
|
9388
9331
|
} catch (error) {
|
|
9389
|
-
|
|
9332
|
+
logger11.debug("Failed to get current commit hash", { projectPath, error });
|
|
9390
9333
|
return null;
|
|
9391
9334
|
}
|
|
9392
9335
|
}
|
|
@@ -9396,7 +9339,7 @@ var GitManager = class {
|
|
|
9396
9339
|
static createCommit(message, projectPath) {
|
|
9397
9340
|
try {
|
|
9398
9341
|
if (!this.isGitRepository(projectPath)) {
|
|
9399
|
-
|
|
9342
|
+
logger11.debug("Not a git repository, skipping commit", { projectPath });
|
|
9400
9343
|
return false;
|
|
9401
9344
|
}
|
|
9402
9345
|
execSync2("git add .", {
|
|
@@ -9409,10 +9352,10 @@ var GitManager = class {
|
|
|
9409
9352
|
encoding: "utf-8",
|
|
9410
9353
|
stdio: ["ignore", "pipe", "ignore"]
|
|
9411
9354
|
});
|
|
9412
|
-
|
|
9355
|
+
logger11.debug("Created commit successfully", { projectPath, message });
|
|
9413
9356
|
return true;
|
|
9414
9357
|
} catch (error) {
|
|
9415
|
-
|
|
9358
|
+
logger11.debug("Failed to create commit", {
|
|
9416
9359
|
projectPath,
|
|
9417
9360
|
message,
|
|
9418
9361
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -9426,7 +9369,7 @@ var GitManager = class {
|
|
|
9426
9369
|
static hasUncommittedChanges(projectPath) {
|
|
9427
9370
|
try {
|
|
9428
9371
|
if (!this.isGitRepository(projectPath)) {
|
|
9429
|
-
|
|
9372
|
+
logger11.debug("Not a git repository, no uncommitted changes", {
|
|
9430
9373
|
projectPath
|
|
9431
9374
|
});
|
|
9432
9375
|
return false;
|
|
@@ -9437,13 +9380,13 @@ var GitManager = class {
|
|
|
9437
9380
|
stdio: ["ignore", "pipe", "ignore"]
|
|
9438
9381
|
}).trim();
|
|
9439
9382
|
const hasChanges = status.length > 0;
|
|
9440
|
-
|
|
9383
|
+
logger11.debug("Checked for uncommitted changes", {
|
|
9441
9384
|
projectPath,
|
|
9442
9385
|
hasChanges
|
|
9443
9386
|
});
|
|
9444
9387
|
return hasChanges;
|
|
9445
9388
|
} catch (error) {
|
|
9446
|
-
|
|
9389
|
+
logger11.debug("Failed to check for uncommitted changes", {
|
|
9447
9390
|
projectPath,
|
|
9448
9391
|
error: error instanceof Error ? error.message : String(error)
|
|
9449
9392
|
});
|
|
@@ -9451,7 +9394,7 @@ var GitManager = class {
|
|
|
9451
9394
|
}
|
|
9452
9395
|
}
|
|
9453
9396
|
};
|
|
9454
|
-
var
|
|
9397
|
+
var defaultLogger3 = createLogger("TaskBackend");
|
|
9455
9398
|
var TaskBackendManager = class _TaskBackendManager {
|
|
9456
9399
|
/**
|
|
9457
9400
|
* Detect and validate the requested task backend
|
|
@@ -9463,18 +9406,19 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
9463
9406
|
* When TASK_BACKEND is explicitly set:
|
|
9464
9407
|
* - Uses the specified backend (markdown or beads)
|
|
9465
9408
|
* - For beads, validates availability and provides setup instructions if not available
|
|
9409
|
+
*
|
|
9466
9410
|
*/
|
|
9467
|
-
static detectTaskBackend() {
|
|
9411
|
+
static detectTaskBackend(logger24 = defaultLogger3) {
|
|
9468
9412
|
const envBackend = process.env["TASK_BACKEND"]?.toLowerCase().trim();
|
|
9469
9413
|
if (envBackend && !["markdown", "beads"].includes(envBackend)) {
|
|
9470
|
-
|
|
9414
|
+
logger24.debug("Invalid TASK_BACKEND value, treating as not set", {
|
|
9471
9415
|
envBackend
|
|
9472
9416
|
});
|
|
9473
9417
|
}
|
|
9474
9418
|
if (!envBackend || !["markdown", "beads"].includes(envBackend)) {
|
|
9475
|
-
const beadsAvailable2 = _TaskBackendManager.checkBeadsAvailability();
|
|
9419
|
+
const beadsAvailable2 = _TaskBackendManager.checkBeadsAvailability(logger24);
|
|
9476
9420
|
if (beadsAvailable2.isAvailable) {
|
|
9477
|
-
|
|
9421
|
+
logger24.debug("Auto-detected beads backend (bd command available)", {
|
|
9478
9422
|
reason: "TASK_BACKEND not set, bd command found"
|
|
9479
9423
|
});
|
|
9480
9424
|
return {
|
|
@@ -9482,7 +9426,7 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
9482
9426
|
isAvailable: true
|
|
9483
9427
|
};
|
|
9484
9428
|
}
|
|
9485
|
-
|
|
9429
|
+
logger24.debug("Using markdown backend (bd command not available)", {
|
|
9486
9430
|
reason: "TASK_BACKEND not set, bd command not found"
|
|
9487
9431
|
});
|
|
9488
9432
|
return {
|
|
@@ -9492,15 +9436,15 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
9492
9436
|
}
|
|
9493
9437
|
const backend = envBackend;
|
|
9494
9438
|
if (backend === "markdown") {
|
|
9495
|
-
|
|
9439
|
+
logger24.debug("Using explicitly configured markdown backend");
|
|
9496
9440
|
return {
|
|
9497
9441
|
backend: "markdown",
|
|
9498
9442
|
isAvailable: true
|
|
9499
9443
|
};
|
|
9500
9444
|
}
|
|
9501
|
-
const beadsAvailable = _TaskBackendManager.checkBeadsAvailability();
|
|
9445
|
+
const beadsAvailable = _TaskBackendManager.checkBeadsAvailability(logger24);
|
|
9502
9446
|
if (beadsAvailable.isAvailable) {
|
|
9503
|
-
|
|
9447
|
+
logger24.debug("Using explicitly configured beads backend");
|
|
9504
9448
|
return {
|
|
9505
9449
|
backend: "beads",
|
|
9506
9450
|
isAvailable: true
|
|
@@ -9515,14 +9459,14 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
9515
9459
|
/**
|
|
9516
9460
|
* Check if beads command is available and functional
|
|
9517
9461
|
*/
|
|
9518
|
-
static checkBeadsAvailability() {
|
|
9462
|
+
static checkBeadsAvailability(logger24 = defaultLogger3) {
|
|
9519
9463
|
try {
|
|
9520
9464
|
const output = execSync3("bd --version", {
|
|
9521
9465
|
encoding: "utf-8",
|
|
9522
9466
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9523
9467
|
timeout: 5e3
|
|
9524
9468
|
});
|
|
9525
|
-
|
|
9469
|
+
logger24.debug("Beads command available", { version: output.trim() });
|
|
9526
9470
|
return { isAvailable: true };
|
|
9527
9471
|
} catch (error) {
|
|
9528
9472
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -9538,7 +9482,7 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
9538
9482
|
errorMessage: "Beads command (bd) timed out. Check if beads is properly installed and configured."
|
|
9539
9483
|
};
|
|
9540
9484
|
}
|
|
9541
|
-
|
|
9485
|
+
logger24.warn("Beads availability check failed", { errorMessage });
|
|
9542
9486
|
return {
|
|
9543
9487
|
isAvailable: false,
|
|
9544
9488
|
errorMessage: `Beads command (bd) check failed: ${errorMessage}`
|
|
@@ -9591,9 +9535,10 @@ export TASK_BACKEND=markdown
|
|
|
9591
9535
|
}
|
|
9592
9536
|
/**
|
|
9593
9537
|
* Validate task backend configuration and throw error if invalid
|
|
9538
|
+
*
|
|
9594
9539
|
*/
|
|
9595
|
-
static validateTaskBackend() {
|
|
9596
|
-
const config = this.detectTaskBackend();
|
|
9540
|
+
static validateTaskBackend(logger24 = defaultLogger3) {
|
|
9541
|
+
const config = this.detectTaskBackend(logger24);
|
|
9597
9542
|
if (!config.isAvailable) {
|
|
9598
9543
|
const setupInstructions = config.backend === "beads" ? this.getBeadsSetupInstructions() : "Task backend validation failed";
|
|
9599
9544
|
throw new Error(`Task backend '${config.backend}' is not available.
|
|
@@ -9602,18 +9547,20 @@ ${config.errorMessage || ""}
|
|
|
9602
9547
|
|
|
9603
9548
|
${setupInstructions}`);
|
|
9604
9549
|
}
|
|
9605
|
-
|
|
9550
|
+
logger24.info("Task backend validated successfully", {
|
|
9606
9551
|
backend: config.backend,
|
|
9607
9552
|
available: config.isAvailable
|
|
9608
9553
|
});
|
|
9609
9554
|
return config;
|
|
9610
9555
|
}
|
|
9611
9556
|
};
|
|
9612
|
-
var
|
|
9557
|
+
var defaultLogger4 = createLogger("BeadsIntegration");
|
|
9613
9558
|
var BeadsIntegration = class {
|
|
9614
9559
|
projectPath;
|
|
9615
|
-
|
|
9560
|
+
logger;
|
|
9561
|
+
constructor(projectPath, logger24 = defaultLogger4) {
|
|
9616
9562
|
this.projectPath = projectPath;
|
|
9563
|
+
this.logger = logger24;
|
|
9617
9564
|
}
|
|
9618
9565
|
/**
|
|
9619
9566
|
* Ensure beads is initialized in the project directory
|
|
@@ -9629,7 +9576,7 @@ var BeadsIntegration = class {
|
|
|
9629
9576
|
} catch (error) {
|
|
9630
9577
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
9631
9578
|
if (errorMessage.includes("not initialized") || errorMessage.includes("no database") || errorMessage.includes("init")) {
|
|
9632
|
-
|
|
9579
|
+
this.logger.info("Beads not initialized, running bd init --no-db", {
|
|
9633
9580
|
projectPath: this.projectPath
|
|
9634
9581
|
});
|
|
9635
9582
|
try {
|
|
@@ -9638,12 +9585,12 @@ var BeadsIntegration = class {
|
|
|
9638
9585
|
encoding: "utf-8",
|
|
9639
9586
|
stdio: ["ignore", "pipe", "pipe"]
|
|
9640
9587
|
});
|
|
9641
|
-
|
|
9588
|
+
this.logger.info("Successfully initialized beads in project", {
|
|
9642
9589
|
projectPath: this.projectPath
|
|
9643
9590
|
});
|
|
9644
9591
|
} catch (initError) {
|
|
9645
9592
|
const initErrorMessage = initError instanceof Error ? initError.message : String(initError);
|
|
9646
|
-
|
|
9593
|
+
this.logger.error("Failed to initialize beads", initError instanceof Error ? initError : new Error(initErrorMessage), { projectPath: this.projectPath });
|
|
9647
9594
|
throw new Error(`Failed to initialize beads: ${initErrorMessage}`);
|
|
9648
9595
|
}
|
|
9649
9596
|
} else {
|
|
@@ -9661,7 +9608,7 @@ var BeadsIntegration = class {
|
|
|
9661
9608
|
const epicDescription = description || `Responsible vibe engineering session using ${workflowName} workflow for ${projectName}`;
|
|
9662
9609
|
const priority = 2;
|
|
9663
9610
|
const command = `bd create "${epicTitle}" --description "${epicDescription}" --priority ${priority}`;
|
|
9664
|
-
|
|
9611
|
+
this.logger.debug("Creating beads project epic", {
|
|
9665
9612
|
command,
|
|
9666
9613
|
projectName,
|
|
9667
9614
|
workflowName,
|
|
@@ -9675,7 +9622,7 @@ var BeadsIntegration = class {
|
|
|
9675
9622
|
});
|
|
9676
9623
|
const match = output.match(/✓ Created issue: ([\w\d.-]+)/) || output.match(/Created issue: ([\w\d.-]+)/) || output.match(/Created (bd-[\w\d.]+)/);
|
|
9677
9624
|
if (!match) {
|
|
9678
|
-
|
|
9625
|
+
this.logger.warn("Failed to extract task ID from beads output", {
|
|
9679
9626
|
command: `bd create "${epicTitle}" --description "${epicDescription}" --priority 2`,
|
|
9680
9627
|
output: output.slice(0, 200)
|
|
9681
9628
|
// Truncated for logging
|
|
@@ -9683,7 +9630,7 @@ var BeadsIntegration = class {
|
|
|
9683
9630
|
throw new Error(`Failed to extract task ID from beads output: ${output.slice(0, 100)}...`);
|
|
9684
9631
|
}
|
|
9685
9632
|
const epicId = match[1] || "";
|
|
9686
|
-
|
|
9633
|
+
this.logger.info("Created beads project epic", {
|
|
9687
9634
|
epicId,
|
|
9688
9635
|
epicTitle,
|
|
9689
9636
|
projectPath: this.projectPath
|
|
@@ -9697,10 +9644,10 @@ var BeadsIntegration = class {
|
|
|
9697
9644
|
workflowName,
|
|
9698
9645
|
projectPath: this.projectPath
|
|
9699
9646
|
};
|
|
9700
|
-
|
|
9647
|
+
this.logger.error("Failed to create beads project epic", error instanceof Error ? error : new Error(errorMessage), commandInfo);
|
|
9701
9648
|
const execError = error;
|
|
9702
9649
|
if (execError?.stderr) {
|
|
9703
|
-
|
|
9650
|
+
this.logger.error("Beads command stderr output", new Error("Command stderr"), {
|
|
9704
9651
|
stderr: execError.stderr.toString(),
|
|
9705
9652
|
...commandInfo
|
|
9706
9653
|
});
|
|
@@ -9716,12 +9663,12 @@ var BeadsIntegration = class {
|
|
|
9716
9663
|
const phaseTasks = [];
|
|
9717
9664
|
const phaseNames = Object.keys(phases);
|
|
9718
9665
|
for (const phase of phaseNames) {
|
|
9719
|
-
const phaseTitle =
|
|
9666
|
+
const phaseTitle = capitalizePhase(phase);
|
|
9720
9667
|
const priority = 3;
|
|
9721
9668
|
const stateDefinition = phases[phase];
|
|
9722
9669
|
const description = (stateDefinition?.default_instructions || `${workflowName} workflow ${phase} phase tasks`).replace(/"/g, '\\"').replace(/\n/g, " ").replace(/\r/g, "").trim();
|
|
9723
9670
|
const command = `bd create "${phaseTitle}" --description "${description}" --parent ${epicId} --priority ${priority}`;
|
|
9724
|
-
|
|
9671
|
+
this.logger.debug("Creating beads phase task", {
|
|
9725
9672
|
command,
|
|
9726
9673
|
phase,
|
|
9727
9674
|
epicId,
|
|
@@ -9735,7 +9682,7 @@ var BeadsIntegration = class {
|
|
|
9735
9682
|
});
|
|
9736
9683
|
const match = output.match(/✓ Created issue: ([\w\d.-]+)/) || output.match(/Created issue: ([\w\d.-]+)/) || output.match(/Created (bd-[\w\d.]+)/);
|
|
9737
9684
|
if (!match) {
|
|
9738
|
-
|
|
9685
|
+
this.logger.warn("Failed to extract phase task ID from beads output", {
|
|
9739
9686
|
command,
|
|
9740
9687
|
output: output.slice(0, 200)
|
|
9741
9688
|
// Truncated for logging
|
|
@@ -9748,7 +9695,7 @@ var BeadsIntegration = class {
|
|
|
9748
9695
|
phaseName: phaseTitle,
|
|
9749
9696
|
taskId: phaseTaskId
|
|
9750
9697
|
});
|
|
9751
|
-
|
|
9698
|
+
this.logger.debug("Created beads phase task", {
|
|
9752
9699
|
phase,
|
|
9753
9700
|
phaseTaskId,
|
|
9754
9701
|
epicId,
|
|
@@ -9762,10 +9709,10 @@ var BeadsIntegration = class {
|
|
|
9762
9709
|
epicId,
|
|
9763
9710
|
projectPath: this.projectPath
|
|
9764
9711
|
};
|
|
9765
|
-
|
|
9712
|
+
this.logger.error("Failed to create beads phase task", error instanceof Error ? error : new Error(errorMessage), commandInfo);
|
|
9766
9713
|
const execError = error;
|
|
9767
9714
|
if (execError?.stderr) {
|
|
9768
|
-
|
|
9715
|
+
this.logger.error("Beads phase command stderr output", new Error("Command stderr"), {
|
|
9769
9716
|
stderr: execError.stderr.toString(),
|
|
9770
9717
|
...commandInfo
|
|
9771
9718
|
});
|
|
@@ -9773,7 +9720,7 @@ var BeadsIntegration = class {
|
|
|
9773
9720
|
throw new Error(`Failed to create beads phase task for ${phase}: ${errorMessage}`);
|
|
9774
9721
|
}
|
|
9775
9722
|
}
|
|
9776
|
-
|
|
9723
|
+
this.logger.info("Created all beads phase tasks", {
|
|
9777
9724
|
count: phaseTasks.length,
|
|
9778
9725
|
epicId,
|
|
9779
9726
|
projectPath: this.projectPath
|
|
@@ -9786,13 +9733,13 @@ var BeadsIntegration = class {
|
|
|
9786
9733
|
*/
|
|
9787
9734
|
async createPhaseDependencies(phaseTasks) {
|
|
9788
9735
|
if (phaseTasks.length < 2) {
|
|
9789
|
-
|
|
9736
|
+
this.logger.debug("Skipping phase dependencies - less than 2 phases", {
|
|
9790
9737
|
phaseCount: phaseTasks.length,
|
|
9791
9738
|
projectPath: this.projectPath
|
|
9792
9739
|
});
|
|
9793
9740
|
return;
|
|
9794
9741
|
}
|
|
9795
|
-
|
|
9742
|
+
this.logger.info("Creating sequential phase dependencies", {
|
|
9796
9743
|
phaseCount: phaseTasks.length,
|
|
9797
9744
|
projectPath: this.projectPath
|
|
9798
9745
|
});
|
|
@@ -9801,7 +9748,7 @@ var BeadsIntegration = class {
|
|
|
9801
9748
|
const currentPhase = phaseTasks[i2];
|
|
9802
9749
|
const nextPhase = phaseTasks[i2 + 1];
|
|
9803
9750
|
if (!currentPhase || !nextPhase) {
|
|
9804
|
-
|
|
9751
|
+
this.logger.warn("Skipping phase dependency - missing phase data", {
|
|
9805
9752
|
currentPhaseIndex: i2,
|
|
9806
9753
|
nextPhaseIndex: i2 + 1,
|
|
9807
9754
|
totalPhases: phaseTasks.length,
|
|
@@ -9815,7 +9762,7 @@ var BeadsIntegration = class {
|
|
|
9815
9762
|
continue;
|
|
9816
9763
|
}
|
|
9817
9764
|
const command = `bd dep ${currentPhase.taskId} --blocks ${nextPhase.taskId}`;
|
|
9818
|
-
|
|
9765
|
+
this.logger.debug("Creating phase dependency", {
|
|
9819
9766
|
command,
|
|
9820
9767
|
currentPhase: currentPhase.phaseName,
|
|
9821
9768
|
nextPhase: nextPhase.phaseName,
|
|
@@ -9829,14 +9776,14 @@ var BeadsIntegration = class {
|
|
|
9829
9776
|
encoding: "utf-8",
|
|
9830
9777
|
stdio: ["ignore", "pipe", "pipe"]
|
|
9831
9778
|
});
|
|
9832
|
-
|
|
9779
|
+
this.logger.debug("Successfully created phase dependency", {
|
|
9833
9780
|
currentPhase: currentPhase.phaseName,
|
|
9834
9781
|
nextPhase: nextPhase.phaseName,
|
|
9835
9782
|
projectPath: this.projectPath
|
|
9836
9783
|
});
|
|
9837
9784
|
} catch (error) {
|
|
9838
9785
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
9839
|
-
|
|
9786
|
+
this.logger.warn("Failed to create phase dependency - continuing anyway", {
|
|
9840
9787
|
error: errorMessage,
|
|
9841
9788
|
command,
|
|
9842
9789
|
currentPhase: currentPhase.phaseName,
|
|
@@ -9845,7 +9792,7 @@ var BeadsIntegration = class {
|
|
|
9845
9792
|
});
|
|
9846
9793
|
const execError = error;
|
|
9847
9794
|
if (execError?.stderr) {
|
|
9848
|
-
|
|
9795
|
+
this.logger.debug("Beads dependency command stderr", {
|
|
9849
9796
|
stderr: execError.stderr.toString(),
|
|
9850
9797
|
command,
|
|
9851
9798
|
projectPath: this.projectPath
|
|
@@ -9859,25 +9806,19 @@ var BeadsIntegration = class {
|
|
|
9859
9806
|
}
|
|
9860
9807
|
}
|
|
9861
9808
|
if (failedDependencies.length > 0) {
|
|
9862
|
-
|
|
9809
|
+
this.logger.warn("Some phase dependencies could not be created - app continues without these dependencies", {
|
|
9863
9810
|
failedCount: failedDependencies.length,
|
|
9864
9811
|
failedDependencies,
|
|
9865
9812
|
projectPath: this.projectPath
|
|
9866
9813
|
});
|
|
9867
9814
|
}
|
|
9868
|
-
|
|
9815
|
+
this.logger.info("Completed phase dependency creation", {
|
|
9869
9816
|
dependencyCount: phaseTasks.length - 1,
|
|
9870
9817
|
successCount: phaseTasks.length - 1 - failedDependencies.length,
|
|
9871
9818
|
failedCount: failedDependencies.length,
|
|
9872
9819
|
projectPath: this.projectPath
|
|
9873
9820
|
});
|
|
9874
9821
|
}
|
|
9875
|
-
/**
|
|
9876
|
-
* Capitalize phase name for display
|
|
9877
|
-
*/
|
|
9878
|
-
capitalizePhase(phase) {
|
|
9879
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
9880
|
-
}
|
|
9881
9822
|
/**
|
|
9882
9823
|
* Validate parameters for epic creation
|
|
9883
9824
|
*/
|
|
@@ -9921,11 +9862,13 @@ var BeadsIntegration = class {
|
|
|
9921
9862
|
}
|
|
9922
9863
|
}
|
|
9923
9864
|
};
|
|
9924
|
-
var
|
|
9865
|
+
var defaultLogger5 = createLogger("BeadsStateManager");
|
|
9925
9866
|
var BeadsStateManager = class {
|
|
9926
9867
|
projectPath;
|
|
9927
|
-
|
|
9868
|
+
logger;
|
|
9869
|
+
constructor(projectPath, logger24 = defaultLogger5) {
|
|
9928
9870
|
this.projectPath = projectPath;
|
|
9871
|
+
this.logger = logger24;
|
|
9929
9872
|
}
|
|
9930
9873
|
/**
|
|
9931
9874
|
* Get the path to the beads state file for a conversation
|
|
@@ -9946,7 +9889,7 @@ var BeadsStateManager = class {
|
|
|
9946
9889
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9947
9890
|
};
|
|
9948
9891
|
await this.saveState(state);
|
|
9949
|
-
|
|
9892
|
+
this.logger.info("Created beads conversation state", {
|
|
9950
9893
|
conversationId,
|
|
9951
9894
|
epicId,
|
|
9952
9895
|
phaseCount: phaseTasks.length,
|
|
@@ -9963,7 +9906,7 @@ var BeadsStateManager = class {
|
|
|
9963
9906
|
await access5(statePath);
|
|
9964
9907
|
const content = await readFile3(statePath, "utf-8");
|
|
9965
9908
|
const state = JSON.parse(content);
|
|
9966
|
-
|
|
9909
|
+
this.logger.debug("Retrieved beads conversation state", {
|
|
9967
9910
|
conversationId,
|
|
9968
9911
|
epicId: state.epicId,
|
|
9969
9912
|
phaseCount: state.phaseTasks.length,
|
|
@@ -9972,14 +9915,14 @@ var BeadsStateManager = class {
|
|
|
9972
9915
|
return state;
|
|
9973
9916
|
} catch (error) {
|
|
9974
9917
|
if (error.code === "ENOENT") {
|
|
9975
|
-
|
|
9918
|
+
this.logger.debug("No beads state found for conversation", {
|
|
9976
9919
|
conversationId,
|
|
9977
9920
|
projectPath: this.projectPath
|
|
9978
9921
|
});
|
|
9979
9922
|
return null;
|
|
9980
9923
|
}
|
|
9981
9924
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
9982
|
-
|
|
9925
|
+
this.logger.warn("Failed to read beads state file", {
|
|
9983
9926
|
error: errorMessage,
|
|
9984
9927
|
conversationId,
|
|
9985
9928
|
statePath,
|
|
@@ -9998,7 +9941,7 @@ var BeadsStateManager = class {
|
|
|
9998
9941
|
}
|
|
9999
9942
|
const phaseTask = state.phaseTasks.find((task) => task.phaseId === phase);
|
|
10000
9943
|
if (phaseTask) {
|
|
10001
|
-
|
|
9944
|
+
this.logger.debug("Found phase task ID", {
|
|
10002
9945
|
conversationId,
|
|
10003
9946
|
phase,
|
|
10004
9947
|
taskId: phaseTask.taskId,
|
|
@@ -10006,7 +9949,7 @@ var BeadsStateManager = class {
|
|
|
10006
9949
|
});
|
|
10007
9950
|
return phaseTask.taskId;
|
|
10008
9951
|
}
|
|
10009
|
-
|
|
9952
|
+
this.logger.debug("No task ID found for phase", {
|
|
10010
9953
|
conversationId,
|
|
10011
9954
|
phase,
|
|
10012
9955
|
availablePhases: state.phaseTasks.map((t) => t.phaseId),
|
|
@@ -10020,7 +9963,7 @@ var BeadsStateManager = class {
|
|
|
10020
9963
|
async updateState(conversationId, updates) {
|
|
10021
9964
|
const existingState = await this.getState(conversationId);
|
|
10022
9965
|
if (!existingState) {
|
|
10023
|
-
|
|
9966
|
+
this.logger.warn("Cannot update non-existent beads state", {
|
|
10024
9967
|
conversationId,
|
|
10025
9968
|
projectPath: this.projectPath
|
|
10026
9969
|
});
|
|
@@ -10034,7 +9977,7 @@ var BeadsStateManager = class {
|
|
|
10034
9977
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10035
9978
|
};
|
|
10036
9979
|
await this.saveState(updatedState);
|
|
10037
|
-
|
|
9980
|
+
this.logger.info("Updated beads conversation state", {
|
|
10038
9981
|
conversationId,
|
|
10039
9982
|
updatedFields: Object.keys(updates),
|
|
10040
9983
|
projectPath: this.projectPath
|
|
@@ -10049,21 +9992,21 @@ var BeadsStateManager = class {
|
|
|
10049
9992
|
try {
|
|
10050
9993
|
await access5(statePath);
|
|
10051
9994
|
await writeFile3(statePath + ".backup", await readFile3(statePath));
|
|
10052
|
-
|
|
9995
|
+
this.logger.info("Cleaned up beads conversation state", {
|
|
10053
9996
|
conversationId,
|
|
10054
9997
|
statePath,
|
|
10055
9998
|
projectPath: this.projectPath
|
|
10056
9999
|
});
|
|
10057
10000
|
} catch (error) {
|
|
10058
10001
|
if (error.code === "ENOENT") {
|
|
10059
|
-
|
|
10002
|
+
this.logger.debug("No beads state to clean up", {
|
|
10060
10003
|
conversationId,
|
|
10061
10004
|
projectPath: this.projectPath
|
|
10062
10005
|
});
|
|
10063
10006
|
return;
|
|
10064
10007
|
}
|
|
10065
10008
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10066
|
-
|
|
10009
|
+
this.logger.warn("Failed to clean up beads state", {
|
|
10067
10010
|
error: errorMessage,
|
|
10068
10011
|
conversationId,
|
|
10069
10012
|
statePath,
|
|
@@ -10093,7 +10036,7 @@ var BeadsStateManager = class {
|
|
|
10093
10036
|
await mkdir3(stateDir, { recursive: true });
|
|
10094
10037
|
const content = JSON.stringify(state, null, 2);
|
|
10095
10038
|
await writeFile3(statePath, content, "utf-8");
|
|
10096
|
-
|
|
10039
|
+
this.logger.debug("Saved beads state to file", {
|
|
10097
10040
|
conversationId: state.conversationId,
|
|
10098
10041
|
statePath,
|
|
10099
10042
|
fileSize: content.length,
|
|
@@ -10101,7 +10044,7 @@ var BeadsStateManager = class {
|
|
|
10101
10044
|
});
|
|
10102
10045
|
} catch (error) {
|
|
10103
10046
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10104
|
-
|
|
10047
|
+
this.logger.error("Failed to save beads state", error instanceof Error ? error : new Error(errorMessage), {
|
|
10105
10048
|
conversationId: state.conversationId,
|
|
10106
10049
|
statePath,
|
|
10107
10050
|
projectPath: this.projectPath
|
|
@@ -10110,7 +10053,7 @@ var BeadsStateManager = class {
|
|
|
10110
10053
|
}
|
|
10111
10054
|
}
|
|
10112
10055
|
};
|
|
10113
|
-
var
|
|
10056
|
+
var logger12 = createLogger("InteractionLogger");
|
|
10114
10057
|
var InteractionLogger = class {
|
|
10115
10058
|
database;
|
|
10116
10059
|
/**
|
|
@@ -10120,7 +10063,7 @@ var InteractionLogger = class {
|
|
|
10120
10063
|
*/
|
|
10121
10064
|
constructor(database) {
|
|
10122
10065
|
this.database = database;
|
|
10123
|
-
|
|
10066
|
+
logger12.debug("InteractionLogger initialized");
|
|
10124
10067
|
}
|
|
10125
10068
|
/**
|
|
10126
10069
|
* Log an interaction with a tool
|
|
@@ -10133,7 +10076,7 @@ var InteractionLogger = class {
|
|
|
10133
10076
|
* @returns Promise that resolves when the log is saved
|
|
10134
10077
|
*/
|
|
10135
10078
|
async logInteraction(conversationId, toolName, inputParams, responseData, currentPhase) {
|
|
10136
|
-
|
|
10079
|
+
logger12.debug("Logging interaction", {
|
|
10137
10080
|
conversationId,
|
|
10138
10081
|
toolName,
|
|
10139
10082
|
currentPhase
|
|
@@ -10149,13 +10092,13 @@ var InteractionLogger = class {
|
|
|
10149
10092
|
timestamp: timestamp2
|
|
10150
10093
|
};
|
|
10151
10094
|
await this.database.logInteraction(log);
|
|
10152
|
-
|
|
10095
|
+
logger12.info("Interaction logged successfully", {
|
|
10153
10096
|
conversationId,
|
|
10154
10097
|
toolName,
|
|
10155
10098
|
timestamp: timestamp2
|
|
10156
10099
|
});
|
|
10157
10100
|
} catch (error) {
|
|
10158
|
-
|
|
10101
|
+
logger12.error("Failed to log interaction", error, {
|
|
10159
10102
|
conversationId,
|
|
10160
10103
|
toolName
|
|
10161
10104
|
});
|
|
@@ -10168,16 +10111,16 @@ var InteractionLogger = class {
|
|
|
10168
10111
|
* @returns Promise that resolves to an array of interaction logs
|
|
10169
10112
|
*/
|
|
10170
10113
|
async getInteractionsByConversationId(conversationId) {
|
|
10171
|
-
|
|
10114
|
+
logger12.debug("Getting interactions by conversation ID", { conversationId });
|
|
10172
10115
|
try {
|
|
10173
10116
|
const logs = await this.database.getInteractionsByConversationId(conversationId);
|
|
10174
|
-
|
|
10117
|
+
logger12.info("Retrieved interaction logs", {
|
|
10175
10118
|
conversationId,
|
|
10176
10119
|
count: logs.length
|
|
10177
10120
|
});
|
|
10178
10121
|
return logs;
|
|
10179
10122
|
} catch (error) {
|
|
10180
|
-
|
|
10123
|
+
logger12.error("Failed to get interaction logs", error, {
|
|
10181
10124
|
conversationId
|
|
10182
10125
|
});
|
|
10183
10126
|
throw error;
|
|
@@ -10186,11 +10129,11 @@ var InteractionLogger = class {
|
|
|
10186
10129
|
};
|
|
10187
10130
|
var InstructionGenerator = class {
|
|
10188
10131
|
projectDocsManager;
|
|
10189
|
-
constructor(
|
|
10190
|
-
this.projectDocsManager = new ProjectDocsManager();
|
|
10132
|
+
constructor(logger24 = createLogger("InstructionGenerator")) {
|
|
10133
|
+
this.projectDocsManager = new ProjectDocsManager(logger24);
|
|
10191
10134
|
}
|
|
10192
10135
|
/**
|
|
10193
|
-
*
|
|
10136
|
+
* No-op: all phase context is provided per-call via InstructionContext.
|
|
10194
10137
|
*/
|
|
10195
10138
|
setStateMachine(_stateMachine) {
|
|
10196
10139
|
return;
|
|
@@ -10203,7 +10146,6 @@ var InstructionGenerator = class {
|
|
|
10203
10146
|
const enhancedInstructions = await this.enhanceInstructions(substitutedInstructions, context);
|
|
10204
10147
|
return {
|
|
10205
10148
|
instructions: enhancedInstructions,
|
|
10206
|
-
planFileGuidance: "Task management guidance is now included in main instructions",
|
|
10207
10149
|
metadata: {
|
|
10208
10150
|
phase: context.phase,
|
|
10209
10151
|
planFilePath: context.conversationContext.planFilePath,
|
|
@@ -10234,41 +10176,34 @@ var InstructionGenerator = class {
|
|
|
10234
10176
|
* Enhance base instructions with context-specific information
|
|
10235
10177
|
*/
|
|
10236
10178
|
async enhanceInstructions(baseInstructions, context) {
|
|
10237
|
-
const { phase, conversationContext,
|
|
10238
|
-
const phaseName =
|
|
10179
|
+
const { phase, conversationContext, allowedFilePatterns } = context;
|
|
10180
|
+
const phaseName = capitalizePhase(phase);
|
|
10239
10181
|
let workflowSection = `---
|
|
10240
|
-
**
|
|
10241
|
-
|
|
10242
|
-
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
|
|
10247
|
-
|
|
10248
|
-
workflowSection += "\n\nCall `whats_next()` after each user message.";
|
|
10182
|
+
**Read \`${conversationContext.planFilePath}\`** for context.
|
|
10183
|
+
- Focus on "${phaseName}" tasks, log decisions in "Key Decisions"
|
|
10184
|
+
- Do NOT use other task/todo tools - use only the plan file for task tracking`;
|
|
10185
|
+
if (allowedFilePatterns && allowedFilePatterns.length > 0 && !allowedFilePatterns.includes("**/*") && !allowedFilePatterns.includes("*")) {
|
|
10186
|
+
workflowSection += `
|
|
10187
|
+
- Files allowed: \`${allowedFilePatterns.join("`, `")}\``;
|
|
10188
|
+
}
|
|
10189
|
+
workflowSection += "\n\nCall `whats_next()` after user messages.";
|
|
10249
10190
|
return `## ${phaseName} Phase
|
|
10250
10191
|
|
|
10251
10192
|
${baseInstructions}
|
|
10252
10193
|
|
|
10253
10194
|
${workflowSection}`;
|
|
10254
10195
|
}
|
|
10255
|
-
/**
|
|
10256
|
-
* Capitalize phase name for display
|
|
10257
|
-
*/
|
|
10258
|
-
capitalizePhase(phase) {
|
|
10259
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
10260
|
-
}
|
|
10261
10196
|
};
|
|
10262
|
-
var
|
|
10197
|
+
var logger13 = createLogger("SystemPromptGenerator");
|
|
10263
10198
|
function generateSystemPrompt(stateMachine) {
|
|
10264
|
-
|
|
10199
|
+
logger13.debug("Generating system prompt from state machine definition", {
|
|
10265
10200
|
stateMachineName: stateMachine.name,
|
|
10266
10201
|
phaseCount: Object.keys(stateMachine.states).length
|
|
10267
10202
|
});
|
|
10268
10203
|
return generateSimpleSystemPrompt(stateMachine);
|
|
10269
10204
|
}
|
|
10270
10205
|
function generateSimpleSystemPrompt(_stateMachine) {
|
|
10271
|
-
|
|
10206
|
+
logger13.debug("Generating system prompt");
|
|
10272
10207
|
const systemPrompt = `
|
|
10273
10208
|
You are an AI assistant that helps users develop software features using the workflows server.
|
|
10274
10209
|
|
|
@@ -10279,17 +10214,18 @@ Each tool call returns a JSON response with an "instructions" field. Follow thes
|
|
|
10279
10214
|
Use the development plan which you will retrieve via whats_next() to record important insights and decisions as per the structure of the plan.
|
|
10280
10215
|
|
|
10281
10216
|
Do not use your own task management tools.`;
|
|
10282
|
-
|
|
10217
|
+
logger13.info("System prompt generated successfully", {
|
|
10283
10218
|
promptLength: systemPrompt.length
|
|
10284
10219
|
});
|
|
10285
10220
|
return systemPrompt;
|
|
10286
10221
|
}
|
|
10287
|
-
var
|
|
10288
|
-
function normalizeProjectPath(projectPath) {
|
|
10222
|
+
var defaultLogger6 = createLogger("ServerHelpers");
|
|
10223
|
+
function normalizeProjectPath(projectPath, logger24) {
|
|
10224
|
+
const log = logger24 ?? defaultLogger6;
|
|
10289
10225
|
const path6 = projectPath || process.cwd();
|
|
10290
10226
|
if (path6 === "/" || path6 === "") {
|
|
10291
10227
|
const homePath = homedir();
|
|
10292
|
-
|
|
10228
|
+
log.info("Invalid project path detected, using home directory", {
|
|
10293
10229
|
originalPath: path6,
|
|
10294
10230
|
normalizedPath: homePath
|
|
10295
10231
|
});
|
|
@@ -10312,14 +10248,18 @@ function createErrorResult(error, metadata) {
|
|
|
10312
10248
|
metadata
|
|
10313
10249
|
};
|
|
10314
10250
|
}
|
|
10315
|
-
async function safeExecute(operation, errorContext) {
|
|
10251
|
+
async function safeExecute(operation, errorContext, logger24) {
|
|
10252
|
+
const log = logger24 ?? defaultLogger6;
|
|
10316
10253
|
try {
|
|
10317
10254
|
const result = await operation();
|
|
10318
10255
|
return createSuccessResult(result);
|
|
10319
10256
|
} catch (error) {
|
|
10320
10257
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
10321
10258
|
const contextualError = errorContext ? `${errorContext}: ${errorMessage}` : errorMessage;
|
|
10322
|
-
|
|
10259
|
+
const isExpectedError = errorMessage.includes("CONVERSATION_NOT_FOUND") || errorMessage.includes("Invalid workflow:");
|
|
10260
|
+
if (!isExpectedError) {
|
|
10261
|
+
log.error("Operation failed", error, { errorContext });
|
|
10262
|
+
}
|
|
10323
10263
|
return createErrorResult(contextualError);
|
|
10324
10264
|
}
|
|
10325
10265
|
}
|
|
@@ -10383,14 +10323,16 @@ function generateWorkflowDescription(workflows) {
|
|
|
10383
10323
|
description += "\u2022 **custom**: Use custom workflow from .vibe/workflows in your project\n\n";
|
|
10384
10324
|
return description;
|
|
10385
10325
|
}
|
|
10386
|
-
function logHandlerExecution(handlerName, args) {
|
|
10387
|
-
|
|
10326
|
+
function logHandlerExecution(handlerName, args, logger24) {
|
|
10327
|
+
const log = logger24 ?? defaultLogger6;
|
|
10328
|
+
log.debug(`Executing ${handlerName} handler`, {
|
|
10388
10329
|
handlerName,
|
|
10389
10330
|
argsKeys: Object.keys(args || {})
|
|
10390
10331
|
});
|
|
10391
10332
|
}
|
|
10392
|
-
function logHandlerCompletion(handlerName, result) {
|
|
10393
|
-
|
|
10333
|
+
function logHandlerCompletion(handlerName, result, logger24) {
|
|
10334
|
+
const log = logger24 ?? defaultLogger6;
|
|
10335
|
+
log.debug(`Completed ${handlerName} handler`, {
|
|
10394
10336
|
handlerName,
|
|
10395
10337
|
success: result.success,
|
|
10396
10338
|
hasData: !!result.data,
|
|
@@ -10418,12 +10360,14 @@ var notificationService = new NotificationService();
|
|
|
10418
10360
|
var PluginRegistry = class {
|
|
10419
10361
|
plugins = /* @__PURE__ */ new Map();
|
|
10420
10362
|
/**
|
|
10421
|
-
* Register a plugin
|
|
10363
|
+
* Register a plugin.
|
|
10364
|
+
*
|
|
10365
|
+
* Note: Plugins are always registered regardless of isEnabled() state.
|
|
10366
|
+
* The isEnabled() check happens at hook execution time in getEnabledPlugins().
|
|
10367
|
+
* This allows plugins to activate/deactivate dynamically based on conditions
|
|
10368
|
+
* that may change after registration (e.g., backend availability).
|
|
10422
10369
|
*/
|
|
10423
10370
|
registerPlugin(plugin) {
|
|
10424
|
-
if (!plugin.isEnabled()) {
|
|
10425
|
-
return;
|
|
10426
|
-
}
|
|
10427
10371
|
const name = plugin.getName();
|
|
10428
10372
|
if (this.plugins.has(name)) {
|
|
10429
10373
|
throw new Error(`Plugin with name '${name}' is already registered`);
|
|
@@ -10535,11 +10479,13 @@ var PluginRegistry = class {
|
|
|
10535
10479
|
this.plugins.clear();
|
|
10536
10480
|
}
|
|
10537
10481
|
};
|
|
10538
|
-
var
|
|
10482
|
+
var defaultLogger7 = createLogger("BeadsTaskBackendClient");
|
|
10539
10483
|
var BeadsTaskBackendClient = class {
|
|
10540
10484
|
projectPath;
|
|
10541
|
-
|
|
10485
|
+
logger;
|
|
10486
|
+
constructor(projectPath, logger24) {
|
|
10542
10487
|
this.projectPath = projectPath;
|
|
10488
|
+
this.logger = logger24 ?? defaultLogger7;
|
|
10543
10489
|
}
|
|
10544
10490
|
/**
|
|
10545
10491
|
* Execute a beads command safely
|
|
@@ -10547,7 +10493,7 @@ var BeadsTaskBackendClient = class {
|
|
|
10547
10493
|
async executeBeadsCommand(args) {
|
|
10548
10494
|
try {
|
|
10549
10495
|
const command = `bd ${args.join(" ")}`;
|
|
10550
|
-
|
|
10496
|
+
this.logger.debug("Executing beads command", {
|
|
10551
10497
|
command,
|
|
10552
10498
|
projectPath: this.projectPath
|
|
10553
10499
|
});
|
|
@@ -10559,7 +10505,7 @@ var BeadsTaskBackendClient = class {
|
|
|
10559
10505
|
return { success: true, stdout };
|
|
10560
10506
|
} catch (error) {
|
|
10561
10507
|
const execError = error;
|
|
10562
|
-
|
|
10508
|
+
this.logger.warn("Beads command failed", {
|
|
10563
10509
|
args,
|
|
10564
10510
|
error: error instanceof Error ? error.message : String(error),
|
|
10565
10511
|
stderr: execError.stderr,
|
|
@@ -10690,18 +10636,29 @@ var BeadsTaskBackendClient = class {
|
|
|
10690
10636
|
}
|
|
10691
10637
|
}
|
|
10692
10638
|
};
|
|
10693
|
-
var logger21 = createLogger("BeadsPlugin");
|
|
10694
10639
|
var BeadsPlugin = class {
|
|
10695
10640
|
projectPath;
|
|
10696
10641
|
beadsStateManager;
|
|
10697
10642
|
beadsTaskBackendClient;
|
|
10698
10643
|
planManager;
|
|
10644
|
+
logger;
|
|
10645
|
+
loggerFactory;
|
|
10699
10646
|
constructor(options) {
|
|
10700
10647
|
this.projectPath = options.projectPath;
|
|
10701
|
-
this.
|
|
10702
|
-
this.
|
|
10648
|
+
this.loggerFactory = options.loggerFactory;
|
|
10649
|
+
this.logger = options.loggerFactory ? options.loggerFactory("BeadsPlugin") : createLogger("BeadsPlugin");
|
|
10650
|
+
this.beadsStateManager = new BeadsStateManager(
|
|
10651
|
+
this.projectPath,
|
|
10652
|
+
options.loggerFactory ? options.loggerFactory("BeadsStateManager") : void 0
|
|
10653
|
+
);
|
|
10654
|
+
this.beadsTaskBackendClient = new BeadsTaskBackendClient(
|
|
10655
|
+
this.projectPath,
|
|
10656
|
+
options.loggerFactory ? options.loggerFactory("BeadsTaskBackendClient") : void 0
|
|
10657
|
+
);
|
|
10703
10658
|
this.planManager = new PlanManager();
|
|
10704
|
-
|
|
10659
|
+
this.logger.debug("BeadsPlugin initialized", {
|
|
10660
|
+
projectPath: this.projectPath
|
|
10661
|
+
});
|
|
10705
10662
|
}
|
|
10706
10663
|
getName() {
|
|
10707
10664
|
return "BeadsPlugin";
|
|
@@ -10710,9 +10667,9 @@ var BeadsPlugin = class {
|
|
|
10710
10667
|
return 100;
|
|
10711
10668
|
}
|
|
10712
10669
|
isEnabled() {
|
|
10713
|
-
const taskBackendConfig = TaskBackendManager.detectTaskBackend();
|
|
10670
|
+
const taskBackendConfig = TaskBackendManager.detectTaskBackend(this.logger);
|
|
10714
10671
|
const enabled = taskBackendConfig.backend === "beads" && taskBackendConfig.isAvailable;
|
|
10715
|
-
|
|
10672
|
+
this.logger.debug("BeadsPlugin enablement check", {
|
|
10716
10673
|
backend: taskBackendConfig.backend,
|
|
10717
10674
|
isAvailable: taskBackendConfig.isAvailable,
|
|
10718
10675
|
autoDetected: !process.env["TASK_BACKEND"],
|
|
@@ -10724,7 +10681,8 @@ var BeadsPlugin = class {
|
|
|
10724
10681
|
return {
|
|
10725
10682
|
afterStartDevelopment: this.handleAfterStartDevelopment.bind(this),
|
|
10726
10683
|
beforePhaseTransition: this.handleBeforePhaseTransition.bind(this),
|
|
10727
|
-
afterPlanFileCreated: this.handleAfterPlanFileCreated.bind(this)
|
|
10684
|
+
afterPlanFileCreated: this.handleAfterPlanFileCreated.bind(this),
|
|
10685
|
+
afterInstructionsGenerated: this.handleAfterInstructionsGenerated.bind(this)
|
|
10728
10686
|
};
|
|
10729
10687
|
}
|
|
10730
10688
|
/**
|
|
@@ -10732,7 +10690,7 @@ var BeadsPlugin = class {
|
|
|
10732
10690
|
* Replaces validateBeadsTaskCompletion() method from proceed-to-phase.ts
|
|
10733
10691
|
*/
|
|
10734
10692
|
async handleBeforePhaseTransition(context, currentPhase, targetPhase) {
|
|
10735
|
-
|
|
10693
|
+
this.logger.info(
|
|
10736
10694
|
"BeadsPlugin: Validating task completion before phase transition",
|
|
10737
10695
|
{
|
|
10738
10696
|
conversationId: context.conversationId,
|
|
@@ -10747,7 +10705,7 @@ var BeadsPlugin = class {
|
|
|
10747
10705
|
targetPhase,
|
|
10748
10706
|
context.projectPath
|
|
10749
10707
|
);
|
|
10750
|
-
|
|
10708
|
+
this.logger.info(
|
|
10751
10709
|
"BeadsPlugin: Task validation passed, allowing phase transition",
|
|
10752
10710
|
{
|
|
10753
10711
|
conversationId: context.conversationId,
|
|
@@ -10756,7 +10714,7 @@ var BeadsPlugin = class {
|
|
|
10756
10714
|
}
|
|
10757
10715
|
);
|
|
10758
10716
|
} catch (error) {
|
|
10759
|
-
|
|
10717
|
+
this.logger.info(
|
|
10760
10718
|
"BeadsPlugin: Task validation failed, blocking phase transition",
|
|
10761
10719
|
{
|
|
10762
10720
|
conversationId: context.conversationId,
|
|
@@ -10774,20 +10732,25 @@ var BeadsPlugin = class {
|
|
|
10774
10732
|
* Implements graceful degradation: continues app operation even if beads operations fail
|
|
10775
10733
|
*/
|
|
10776
10734
|
async handleAfterStartDevelopment(context, args, _result) {
|
|
10777
|
-
|
|
10735
|
+
this.logger.info("BeadsPlugin: Setting up beads integration", {
|
|
10778
10736
|
conversationId: context.conversationId,
|
|
10779
10737
|
workflow: args.workflow,
|
|
10780
10738
|
projectPath: context.projectPath
|
|
10781
10739
|
});
|
|
10782
10740
|
if (!context.stateMachine) {
|
|
10783
|
-
|
|
10784
|
-
|
|
10741
|
+
this.logger.error(
|
|
10742
|
+
"BeadsPlugin: State machine not provided in plugin context"
|
|
10743
|
+
);
|
|
10744
|
+
this.logger.warn(
|
|
10785
10745
|
"BeadsPlugin: Beads integration disabled - continuing without beads"
|
|
10786
10746
|
);
|
|
10787
10747
|
return;
|
|
10788
10748
|
}
|
|
10789
10749
|
try {
|
|
10790
|
-
const beadsIntegration = new BeadsIntegration(
|
|
10750
|
+
const beadsIntegration = new BeadsIntegration(
|
|
10751
|
+
context.projectPath,
|
|
10752
|
+
this.loggerFactory ? this.loggerFactory("BeadsIntegration") : void 0
|
|
10753
|
+
);
|
|
10791
10754
|
const projectName = getPathBasename(
|
|
10792
10755
|
context.projectPath,
|
|
10793
10756
|
"Unknown Project"
|
|
@@ -10799,7 +10762,7 @@ var BeadsPlugin = class {
|
|
|
10799
10762
|
);
|
|
10800
10763
|
goalDescription = this.extractGoalFromPlan(planFileContent);
|
|
10801
10764
|
} catch (error) {
|
|
10802
|
-
|
|
10765
|
+
this.logger.warn("BeadsPlugin: Could not extract goal from plan file", {
|
|
10803
10766
|
error: error instanceof Error ? error.message : String(error),
|
|
10804
10767
|
planFilePath: context.planFilePath
|
|
10805
10768
|
});
|
|
@@ -10815,7 +10778,7 @@ var BeadsPlugin = class {
|
|
|
10815
10778
|
);
|
|
10816
10779
|
} catch (error) {
|
|
10817
10780
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10818
|
-
|
|
10781
|
+
this.logger.warn(
|
|
10819
10782
|
"BeadsPlugin: Failed to create beads project epic - continuing without beads integration",
|
|
10820
10783
|
{
|
|
10821
10784
|
error: errorMsg,
|
|
@@ -10833,7 +10796,7 @@ var BeadsPlugin = class {
|
|
|
10833
10796
|
);
|
|
10834
10797
|
} catch (error) {
|
|
10835
10798
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10836
|
-
|
|
10799
|
+
this.logger.warn(
|
|
10837
10800
|
"BeadsPlugin: Failed to create beads phase tasks - continuing without phase tracking",
|
|
10838
10801
|
{
|
|
10839
10802
|
error: errorMsg,
|
|
@@ -10846,7 +10809,7 @@ var BeadsPlugin = class {
|
|
|
10846
10809
|
await beadsIntegration.createPhaseDependencies(phaseTasks);
|
|
10847
10810
|
} catch (error) {
|
|
10848
10811
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10849
|
-
|
|
10812
|
+
this.logger.warn(
|
|
10850
10813
|
"BeadsPlugin: Failed to create phase dependencies - continuing without dependencies",
|
|
10851
10814
|
{
|
|
10852
10815
|
error: errorMsg,
|
|
@@ -10861,7 +10824,7 @@ var BeadsPlugin = class {
|
|
|
10861
10824
|
);
|
|
10862
10825
|
} catch (error) {
|
|
10863
10826
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10864
|
-
|
|
10827
|
+
this.logger.warn(
|
|
10865
10828
|
"BeadsPlugin: Failed to update plan file with beads task IDs - continuing without plan file updates",
|
|
10866
10829
|
{
|
|
10867
10830
|
error: errorMsg,
|
|
@@ -10877,7 +10840,7 @@ var BeadsPlugin = class {
|
|
|
10877
10840
|
);
|
|
10878
10841
|
} catch (error) {
|
|
10879
10842
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10880
|
-
|
|
10843
|
+
this.logger.warn(
|
|
10881
10844
|
"BeadsPlugin: Failed to create beads state - continuing without state persistence",
|
|
10882
10845
|
{
|
|
10883
10846
|
error: errorMsg,
|
|
@@ -10885,7 +10848,7 @@ var BeadsPlugin = class {
|
|
|
10885
10848
|
}
|
|
10886
10849
|
);
|
|
10887
10850
|
}
|
|
10888
|
-
|
|
10851
|
+
this.logger.info("BeadsPlugin: Beads integration setup complete", {
|
|
10889
10852
|
conversationId: context.conversationId,
|
|
10890
10853
|
epicId,
|
|
10891
10854
|
phaseCount: phaseTasks?.length || 0,
|
|
@@ -10893,7 +10856,7 @@ var BeadsPlugin = class {
|
|
|
10893
10856
|
});
|
|
10894
10857
|
} catch (error) {
|
|
10895
10858
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10896
|
-
|
|
10859
|
+
this.logger.warn(
|
|
10897
10860
|
"BeadsPlugin: Unexpected error during beads integration setup - continuing application without beads",
|
|
10898
10861
|
{
|
|
10899
10862
|
error: errorMsg,
|
|
@@ -10914,11 +10877,127 @@ var BeadsPlugin = class {
|
|
|
10914
10877
|
* This hook ensures the plan has the proper structure to receive them.
|
|
10915
10878
|
*/
|
|
10916
10879
|
async handleAfterPlanFileCreated(_context, planFilePath, content) {
|
|
10917
|
-
|
|
10880
|
+
this.logger.debug("BeadsPlugin: afterPlanFileCreated hook invoked", {
|
|
10918
10881
|
planFilePath,
|
|
10919
10882
|
contentLength: content.length
|
|
10920
10883
|
});
|
|
10921
|
-
|
|
10884
|
+
let transformed = content;
|
|
10885
|
+
transformed = transformed.replace(
|
|
10886
|
+
/### Tasks\n- \[ \] \*Tasks will be added as they are identified\*\n\n### Completed\n- \[x\] Created development plan file/g,
|
|
10887
|
+
"<!-- beads-phase-id: TBD -->\n### Tasks\n\n*Tasks managed via `bd` CLI*"
|
|
10888
|
+
);
|
|
10889
|
+
transformed = transformed.replace(
|
|
10890
|
+
/### Tasks\n- \[ \] \*To be added when this phase becomes active\*\n\n### Completed\n\*None yet\*/g,
|
|
10891
|
+
"<!-- beads-phase-id: TBD -->\n### Tasks\n\n*Tasks managed via `bd` CLI*"
|
|
10892
|
+
);
|
|
10893
|
+
transformed = transformed.replace(
|
|
10894
|
+
/\*This plan is maintained by the LLM\. Tool responses provide guidance on which section to focus on and what tasks to work on\.\*/,
|
|
10895
|
+
"*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.*"
|
|
10896
|
+
);
|
|
10897
|
+
this.logger.debug("BeadsPlugin: Plan file transformed for beads", {
|
|
10898
|
+
planFilePath,
|
|
10899
|
+
originalLength: content.length,
|
|
10900
|
+
transformedLength: transformed.length,
|
|
10901
|
+
wasModified: content !== transformed
|
|
10902
|
+
});
|
|
10903
|
+
return transformed;
|
|
10904
|
+
}
|
|
10905
|
+
/**
|
|
10906
|
+
* Handle afterInstructionsGenerated hook
|
|
10907
|
+
* Enriches instructions with beads-specific task management guidance
|
|
10908
|
+
*/
|
|
10909
|
+
async handleAfterInstructionsGenerated(context, instructions) {
|
|
10910
|
+
this.logger.debug("BeadsPlugin: afterInstructionsGenerated hook invoked", {
|
|
10911
|
+
phase: instructions.phase,
|
|
10912
|
+
instructionSource: instructions.instructionSource,
|
|
10913
|
+
planFilePath: instructions.planFilePath
|
|
10914
|
+
});
|
|
10915
|
+
const beadsGuidance = await this.generateBeadsGuidance(
|
|
10916
|
+
context,
|
|
10917
|
+
instructions
|
|
10918
|
+
);
|
|
10919
|
+
let enhanced = instructions.instructions;
|
|
10920
|
+
enhanced += `
|
|
10921
|
+
|
|
10922
|
+
Log decisions in plan file. Use ONLY \`bd\` CLI for tasks (not your own todo tools).${beadsGuidance}`;
|
|
10923
|
+
if (context.planFileExists === false) {
|
|
10924
|
+
enhanced += "\n\n**Note**: Plan file will be created when you first update it.";
|
|
10925
|
+
}
|
|
10926
|
+
enhanced += "\n\nCall `whats_next()` after user messages.";
|
|
10927
|
+
this.logger.debug(
|
|
10928
|
+
"BeadsPlugin: Instructions enriched with beads guidance",
|
|
10929
|
+
{
|
|
10930
|
+
originalLength: instructions.instructions.length,
|
|
10931
|
+
enrichedLength: enhanced.length
|
|
10932
|
+
}
|
|
10933
|
+
);
|
|
10934
|
+
return {
|
|
10935
|
+
...instructions,
|
|
10936
|
+
instructions: enhanced
|
|
10937
|
+
};
|
|
10938
|
+
}
|
|
10939
|
+
/**
|
|
10940
|
+
* Generate beads-specific task management guidance
|
|
10941
|
+
*/
|
|
10942
|
+
async generateBeadsGuidance(_context, instructions) {
|
|
10943
|
+
if (instructions.instructionSource === "whats_next" || instructions.instructionSource === "start_development") {
|
|
10944
|
+
const phaseTaskId = await this.extractPhaseTaskIdFromPlanFile(
|
|
10945
|
+
instructions.planFilePath,
|
|
10946
|
+
instructions.phase
|
|
10947
|
+
);
|
|
10948
|
+
if (!phaseTaskId) {
|
|
10949
|
+
return `
|
|
10950
|
+
|
|
10951
|
+
**Task Management (bd CLI):**
|
|
10952
|
+
Create tasks as sub-tasks of phase task: \`bd create 'title' --parent <phase-task-id>\`
|
|
10953
|
+
List open tasks: \`bd list --parent <phase-task-id> --status open\`
|
|
10954
|
+
Complete tasks: \`bd close <id>\``;
|
|
10955
|
+
}
|
|
10956
|
+
return `
|
|
10957
|
+
|
|
10958
|
+
**Task Management (bd CLI) - Phase: ${phaseTaskId}**
|
|
10959
|
+
Create tasks as sub-tasks: \`bd create 'title' --parent ${phaseTaskId}\`
|
|
10960
|
+
List open tasks: \`bd list --parent ${phaseTaskId} --status open\`
|
|
10961
|
+
Complete tasks: \`bd close <id>\``;
|
|
10962
|
+
}
|
|
10963
|
+
return "";
|
|
10964
|
+
}
|
|
10965
|
+
/**
|
|
10966
|
+
* Extract phase task ID from plan file
|
|
10967
|
+
*/
|
|
10968
|
+
async extractPhaseTaskIdFromPlanFile(planFilePath, phase) {
|
|
10969
|
+
try {
|
|
10970
|
+
const { readFile: readFile5 } = await import("fs/promises");
|
|
10971
|
+
const content = await readFile5(planFilePath, "utf-8");
|
|
10972
|
+
const phaseName = this.capitalizePhase(phase);
|
|
10973
|
+
const phaseHeader = `## ${phaseName}`;
|
|
10974
|
+
const lines = content.split("\n");
|
|
10975
|
+
let foundPhaseHeader = false;
|
|
10976
|
+
for (const line of lines) {
|
|
10977
|
+
if (line.trim() === phaseHeader) {
|
|
10978
|
+
foundPhaseHeader = true;
|
|
10979
|
+
continue;
|
|
10980
|
+
}
|
|
10981
|
+
if (foundPhaseHeader && line.includes("beads-phase-id:")) {
|
|
10982
|
+
const match = line.match(/beads-phase-id:\s*([\w\d.-]+)/);
|
|
10983
|
+
if (match && match[1] && match[1] !== "TBD") {
|
|
10984
|
+
return match[1];
|
|
10985
|
+
}
|
|
10986
|
+
}
|
|
10987
|
+
if (foundPhaseHeader && line.startsWith("##") && line !== phaseHeader) {
|
|
10988
|
+
break;
|
|
10989
|
+
}
|
|
10990
|
+
}
|
|
10991
|
+
return null;
|
|
10992
|
+
} catch (_error) {
|
|
10993
|
+
return null;
|
|
10994
|
+
}
|
|
10995
|
+
}
|
|
10996
|
+
/**
|
|
10997
|
+
* Capitalize phase name for display
|
|
10998
|
+
*/
|
|
10999
|
+
capitalizePhase(phase) {
|
|
11000
|
+
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
10922
11001
|
}
|
|
10923
11002
|
/**
|
|
10924
11003
|
* Validate beads task completion before phase transition
|
|
@@ -10931,14 +11010,14 @@ var BeadsPlugin = class {
|
|
|
10931
11010
|
isAvailable = await this.beadsTaskBackendClient.isAvailable();
|
|
10932
11011
|
} catch (error) {
|
|
10933
11012
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10934
|
-
|
|
11013
|
+
this.logger.warn("BeadsPlugin: Failed to check beads availability", {
|
|
10935
11014
|
error: errorMsg,
|
|
10936
11015
|
conversationId
|
|
10937
11016
|
});
|
|
10938
11017
|
return;
|
|
10939
11018
|
}
|
|
10940
11019
|
if (!isAvailable) {
|
|
10941
|
-
|
|
11020
|
+
this.logger.debug(
|
|
10942
11021
|
"BeadsPlugin: Skipping beads task validation - beads CLI not available",
|
|
10943
11022
|
{
|
|
10944
11023
|
conversationId,
|
|
@@ -10956,7 +11035,7 @@ var BeadsPlugin = class {
|
|
|
10956
11035
|
);
|
|
10957
11036
|
} catch (error) {
|
|
10958
11037
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10959
|
-
|
|
11038
|
+
this.logger.warn("BeadsPlugin: Failed to get beads phase task ID", {
|
|
10960
11039
|
error: errorMsg,
|
|
10961
11040
|
conversationId,
|
|
10962
11041
|
currentPhase
|
|
@@ -10964,7 +11043,7 @@ var BeadsPlugin = class {
|
|
|
10964
11043
|
return;
|
|
10965
11044
|
}
|
|
10966
11045
|
if (!currentPhaseTaskId) {
|
|
10967
|
-
|
|
11046
|
+
this.logger.debug(
|
|
10968
11047
|
"BeadsPlugin: No beads phase task ID found for current phase",
|
|
10969
11048
|
{
|
|
10970
11049
|
conversationId,
|
|
@@ -10975,7 +11054,7 @@ var BeadsPlugin = class {
|
|
|
10975
11054
|
);
|
|
10976
11055
|
return;
|
|
10977
11056
|
}
|
|
10978
|
-
|
|
11057
|
+
this.logger.debug(
|
|
10979
11058
|
"BeadsPlugin: Checking for incomplete beads tasks using task backend client",
|
|
10980
11059
|
{
|
|
10981
11060
|
conversationId,
|
|
@@ -10990,7 +11069,7 @@ var BeadsPlugin = class {
|
|
|
10990
11069
|
);
|
|
10991
11070
|
} catch (error) {
|
|
10992
11071
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
10993
|
-
|
|
11072
|
+
this.logger.warn(
|
|
10994
11073
|
"BeadsPlugin: Failed to validate tasks with beads backend",
|
|
10995
11074
|
{
|
|
10996
11075
|
error: errorMsg,
|
|
@@ -11002,18 +11081,9 @@ var BeadsPlugin = class {
|
|
|
11002
11081
|
}
|
|
11003
11082
|
if (!validationResult.valid) {
|
|
11004
11083
|
const incompleteTasks = validationResult.openTasks || [];
|
|
11005
|
-
const
|
|
11006
|
-
const errorMessage =
|
|
11007
|
-
|
|
11008
|
-
${taskDetails}
|
|
11009
|
-
|
|
11010
|
-
To proceed, check the in-progress-tasks using:
|
|
11011
|
-
|
|
11012
|
-
bd list --parent ${currentPhaseTaskId} --status open
|
|
11013
|
-
|
|
11014
|
-
You can also defer tasks if they're no longer needed:
|
|
11015
|
-
bd defer <task-id> --until tomorrow`;
|
|
11016
|
-
logger21.info(
|
|
11084
|
+
const taskIds = incompleteTasks.map((t) => t.id).join(", ");
|
|
11085
|
+
const errorMessage = `${incompleteTasks.length} incomplete task(s) in ${currentPhase}: ${taskIds}. Complete or defer (\`bd defer <id>\`) before proceeding.`;
|
|
11086
|
+
this.logger.info(
|
|
11017
11087
|
"BeadsPlugin: Blocking phase transition due to incomplete beads tasks",
|
|
11018
11088
|
{
|
|
11019
11089
|
conversationId,
|
|
@@ -11026,7 +11096,7 @@ You can also defer tasks if they're no longer needed:
|
|
|
11026
11096
|
);
|
|
11027
11097
|
throw new Error(errorMessage);
|
|
11028
11098
|
}
|
|
11029
|
-
|
|
11099
|
+
this.logger.info(
|
|
11030
11100
|
"BeadsPlugin: All beads tasks completed in current phase, allowing transition",
|
|
11031
11101
|
{
|
|
11032
11102
|
conversationId,
|
|
@@ -11040,7 +11110,7 @@ You can also defer tasks if they're no longer needed:
|
|
|
11040
11110
|
throw error;
|
|
11041
11111
|
}
|
|
11042
11112
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
11043
|
-
|
|
11113
|
+
this.logger.warn(
|
|
11044
11114
|
"BeadsPlugin: Beads task validation failed, allowing transition to proceed",
|
|
11045
11115
|
{
|
|
11046
11116
|
error: errorMessage,
|
|
@@ -11093,13 +11163,13 @@ You can also defer tasks if they're no longer needed:
|
|
|
11093
11163
|
*/
|
|
11094
11164
|
async updatePlanFileWithPhaseTaskIds(planFilePath, phaseTasks) {
|
|
11095
11165
|
try {
|
|
11096
|
-
const { readFile:
|
|
11166
|
+
const { readFile: readFile5, writeFile: writeFile5 } = await import("fs/promises");
|
|
11097
11167
|
let content;
|
|
11098
11168
|
try {
|
|
11099
|
-
content = await
|
|
11169
|
+
content = await readFile5(planFilePath, "utf-8");
|
|
11100
11170
|
} catch (error) {
|
|
11101
11171
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
11102
|
-
|
|
11172
|
+
this.logger.warn("BeadsPlugin: Failed to read plan file for update", {
|
|
11103
11173
|
error: errorMsg,
|
|
11104
11174
|
planFilePath
|
|
11105
11175
|
});
|
|
@@ -11119,7 +11189,7 @@ You can also defer tasks if they're no longer needed:
|
|
|
11119
11189
|
}
|
|
11120
11190
|
const remainingTBDs = content.match(/<!-- beads-phase-id: TBD -->/g);
|
|
11121
11191
|
if (remainingTBDs && remainingTBDs.length > 0) {
|
|
11122
|
-
|
|
11192
|
+
this.logger.warn(
|
|
11123
11193
|
"BeadsPlugin: Failed to replace all TBD placeholders in plan file",
|
|
11124
11194
|
{
|
|
11125
11195
|
planFilePath,
|
|
@@ -11129,16 +11199,16 @@ You can also defer tasks if they're no longer needed:
|
|
|
11129
11199
|
);
|
|
11130
11200
|
}
|
|
11131
11201
|
try {
|
|
11132
|
-
await
|
|
11202
|
+
await writeFile5(planFilePath, content, "utf-8");
|
|
11133
11203
|
} catch (error) {
|
|
11134
11204
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
11135
|
-
|
|
11205
|
+
this.logger.warn("BeadsPlugin: Failed to write updated plan file", {
|
|
11136
11206
|
error: errorMsg,
|
|
11137
11207
|
planFilePath
|
|
11138
11208
|
});
|
|
11139
11209
|
return;
|
|
11140
11210
|
}
|
|
11141
|
-
|
|
11211
|
+
this.logger.info(
|
|
11142
11212
|
"BeadsPlugin: Successfully updated plan file with beads phase task IDs",
|
|
11143
11213
|
{
|
|
11144
11214
|
planFilePath,
|
|
@@ -11150,7 +11220,7 @@ You can also defer tasks if they're no longer needed:
|
|
|
11150
11220
|
);
|
|
11151
11221
|
} catch (error) {
|
|
11152
11222
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
11153
|
-
|
|
11223
|
+
this.logger.warn(
|
|
11154
11224
|
"BeadsPlugin: Unexpected error while updating plan file with phase task IDs",
|
|
11155
11225
|
{
|
|
11156
11226
|
error: errorMsg,
|
|
@@ -11160,13 +11230,13 @@ You can also defer tasks if they're no longer needed:
|
|
|
11160
11230
|
}
|
|
11161
11231
|
}
|
|
11162
11232
|
};
|
|
11163
|
-
var
|
|
11233
|
+
var logger14 = createLogger("CommitPlugin");
|
|
11164
11234
|
var CommitPlugin = class {
|
|
11165
11235
|
projectPath;
|
|
11166
11236
|
initialCommitHash;
|
|
11167
11237
|
constructor(options) {
|
|
11168
11238
|
this.projectPath = options.projectPath;
|
|
11169
|
-
|
|
11239
|
+
logger14.debug("CommitPlugin initialized", { projectPath: this.projectPath });
|
|
11170
11240
|
}
|
|
11171
11241
|
getName() {
|
|
11172
11242
|
return "CommitPlugin";
|
|
@@ -11177,7 +11247,7 @@ var CommitPlugin = class {
|
|
|
11177
11247
|
isEnabled() {
|
|
11178
11248
|
const behavior = process.env.COMMIT_BEHAVIOR;
|
|
11179
11249
|
const enabled = behavior && ["step", "phase", "end", "none"].includes(behavior);
|
|
11180
|
-
|
|
11250
|
+
logger14.debug("CommitPlugin enablement check", {
|
|
11181
11251
|
COMMIT_BEHAVIOR: behavior,
|
|
11182
11252
|
enabled: !!enabled
|
|
11183
11253
|
});
|
|
@@ -11195,7 +11265,7 @@ var CommitPlugin = class {
|
|
|
11195
11265
|
* Store initial commit hash for potential squashing later
|
|
11196
11266
|
*/
|
|
11197
11267
|
async handleAfterStartDevelopment(context, _args, _result) {
|
|
11198
|
-
|
|
11268
|
+
logger14.info("CommitPlugin: Setting up commit behavior", {
|
|
11199
11269
|
conversationId: context.conversationId,
|
|
11200
11270
|
behavior: process.env.COMMIT_BEHAVIOR,
|
|
11201
11271
|
projectPath: context.projectPath
|
|
@@ -11203,13 +11273,13 @@ var CommitPlugin = class {
|
|
|
11203
11273
|
try {
|
|
11204
11274
|
if (GitManager.isGitRepository(context.projectPath)) {
|
|
11205
11275
|
this.initialCommitHash = GitManager.getCurrentCommitHash(context.projectPath) || void 0;
|
|
11206
|
-
|
|
11276
|
+
logger14.debug("CommitPlugin: Stored initial commit hash", {
|
|
11207
11277
|
conversationId: context.conversationId,
|
|
11208
11278
|
initialCommitHash: this.initialCommitHash
|
|
11209
11279
|
});
|
|
11210
11280
|
}
|
|
11211
11281
|
} catch (error) {
|
|
11212
|
-
|
|
11282
|
+
logger14.warn("CommitPlugin: Failed to get initial commit hash", {
|
|
11213
11283
|
error: error instanceof Error ? error.message : String(error),
|
|
11214
11284
|
conversationId: context.conversationId
|
|
11215
11285
|
});
|
|
@@ -11224,7 +11294,7 @@ var CommitPlugin = class {
|
|
|
11224
11294
|
if (behavior !== "phase" && behavior !== "step") {
|
|
11225
11295
|
return;
|
|
11226
11296
|
}
|
|
11227
|
-
|
|
11297
|
+
logger14.info("CommitPlugin: Creating WIP commit before phase transition", {
|
|
11228
11298
|
conversationId: context.conversationId,
|
|
11229
11299
|
currentPhase,
|
|
11230
11300
|
targetPhase,
|
|
@@ -11232,28 +11302,28 @@ var CommitPlugin = class {
|
|
|
11232
11302
|
});
|
|
11233
11303
|
try {
|
|
11234
11304
|
if (!GitManager.isGitRepository(context.projectPath)) {
|
|
11235
|
-
|
|
11305
|
+
logger14.debug("CommitPlugin: Not a git repository, skipping commit");
|
|
11236
11306
|
return;
|
|
11237
11307
|
}
|
|
11238
11308
|
if (!GitManager.hasUncommittedChanges(context.projectPath)) {
|
|
11239
|
-
|
|
11309
|
+
logger14.debug("CommitPlugin: No uncommitted changes, skipping commit");
|
|
11240
11310
|
return;
|
|
11241
11311
|
}
|
|
11242
11312
|
const message = `WIP: transition to ${targetPhase}`;
|
|
11243
11313
|
const success = GitManager.createCommit(message, context.projectPath);
|
|
11244
11314
|
if (success) {
|
|
11245
|
-
|
|
11315
|
+
logger14.info("CommitPlugin: Created WIP commit successfully", {
|
|
11246
11316
|
conversationId: context.conversationId,
|
|
11247
11317
|
message
|
|
11248
11318
|
});
|
|
11249
11319
|
} else {
|
|
11250
|
-
|
|
11320
|
+
logger14.warn("CommitPlugin: Failed to create WIP commit", {
|
|
11251
11321
|
conversationId: context.conversationId,
|
|
11252
11322
|
message
|
|
11253
11323
|
});
|
|
11254
11324
|
}
|
|
11255
11325
|
} catch (error) {
|
|
11256
|
-
|
|
11326
|
+
logger14.warn("CommitPlugin: Error during phase transition commit", {
|
|
11257
11327
|
error: error instanceof Error ? error.message : String(error),
|
|
11258
11328
|
conversationId: context.conversationId
|
|
11259
11329
|
});
|
|
@@ -11268,7 +11338,7 @@ var CommitPlugin = class {
|
|
|
11268
11338
|
if (!behavior || behavior === "none") {
|
|
11269
11339
|
return content;
|
|
11270
11340
|
}
|
|
11271
|
-
|
|
11341
|
+
logger14.debug("CommitPlugin: Adding final commit task to plan file", {
|
|
11272
11342
|
conversationId: context.conversationId,
|
|
11273
11343
|
behavior,
|
|
11274
11344
|
planFilePath
|
|
@@ -11292,7 +11362,7 @@ var CommitPlugin = class {
|
|
|
11292
11362
|
}
|
|
11293
11363
|
}
|
|
11294
11364
|
if (finalPhaseIndex === -1) {
|
|
11295
|
-
|
|
11365
|
+
logger14.warn(
|
|
11296
11366
|
"CommitPlugin: Could not find final phase to add commit task"
|
|
11297
11367
|
);
|
|
11298
11368
|
return content;
|
|
@@ -11318,14 +11388,14 @@ var CommitPlugin = class {
|
|
|
11318
11388
|
lines.splice(finalPhaseIndex + 1, 0, "", "### Tasks", commitTask);
|
|
11319
11389
|
}
|
|
11320
11390
|
const updatedContent = lines.join("\n");
|
|
11321
|
-
|
|
11391
|
+
logger14.info("CommitPlugin: Added final commit task to plan file", {
|
|
11322
11392
|
conversationId: context.conversationId,
|
|
11323
11393
|
behavior,
|
|
11324
11394
|
commitTask
|
|
11325
11395
|
});
|
|
11326
11396
|
return updatedContent;
|
|
11327
11397
|
} catch (error) {
|
|
11328
|
-
|
|
11398
|
+
logger14.warn("CommitPlugin: Failed to add commit task to plan file", {
|
|
11329
11399
|
error: error instanceof Error ? error.message : String(error),
|
|
11330
11400
|
conversationId: context.conversationId
|
|
11331
11401
|
});
|
|
@@ -11333,408 +11403,15 @@ var CommitPlugin = class {
|
|
|
11333
11403
|
}
|
|
11334
11404
|
}
|
|
11335
11405
|
};
|
|
11336
|
-
var
|
|
11337
|
-
var BeadsPlanManager = class {
|
|
11338
|
-
stateMachine = null;
|
|
11339
|
-
/**
|
|
11340
|
-
* Set the state machine definition for dynamic plan generation
|
|
11341
|
-
*/
|
|
11342
|
-
setStateMachine(stateMachine) {
|
|
11343
|
-
this.stateMachine = stateMachine;
|
|
11344
|
-
logger23.debug("State machine set for beads plan manager", {
|
|
11345
|
-
name: stateMachine.name,
|
|
11346
|
-
phases: Object.keys(stateMachine.states)
|
|
11347
|
-
});
|
|
11348
|
-
}
|
|
11349
|
-
/**
|
|
11350
|
-
* Set the task backend configuration
|
|
11351
|
-
*/
|
|
11352
|
-
setTaskBackend(taskBackend) {
|
|
11353
|
-
logger23.debug("Task backend set for beads plan manager", {
|
|
11354
|
-
backend: taskBackend.backend,
|
|
11355
|
-
available: taskBackend.isAvailable
|
|
11356
|
-
});
|
|
11357
|
-
}
|
|
11358
|
-
/**
|
|
11359
|
-
* Get plan file information
|
|
11360
|
-
*/
|
|
11361
|
-
async getPlanFileInfo(planFilePath) {
|
|
11362
|
-
try {
|
|
11363
|
-
await access6(planFilePath);
|
|
11364
|
-
const content = await readFile4(planFilePath, "utf-8");
|
|
11365
|
-
return {
|
|
11366
|
-
path: planFilePath,
|
|
11367
|
-
exists: true,
|
|
11368
|
-
content
|
|
11369
|
-
};
|
|
11370
|
-
} catch (_error) {
|
|
11371
|
-
return {
|
|
11372
|
-
path: planFilePath,
|
|
11373
|
-
exists: false
|
|
11374
|
-
};
|
|
11375
|
-
}
|
|
11376
|
-
}
|
|
11377
|
-
/**
|
|
11378
|
-
* Create initial plan file if it doesn't exist
|
|
11379
|
-
*/
|
|
11380
|
-
async ensurePlanFile(planFilePath, projectPath, gitBranch) {
|
|
11381
|
-
logger23.debug("Ensuring beads plan file exists", {
|
|
11382
|
-
planFilePath,
|
|
11383
|
-
projectPath,
|
|
11384
|
-
gitBranch
|
|
11385
|
-
});
|
|
11386
|
-
const planInfo = await this.getPlanFileInfo(planFilePath);
|
|
11387
|
-
if (!planInfo.exists) {
|
|
11388
|
-
logger23.info("Plan file not found, creating beads-optimized plan", {
|
|
11389
|
-
planFilePath
|
|
11390
|
-
});
|
|
11391
|
-
await this.createInitialBeadsPlanFile(
|
|
11392
|
-
planFilePath,
|
|
11393
|
-
projectPath,
|
|
11394
|
-
gitBranch
|
|
11395
|
-
);
|
|
11396
|
-
logger23.info("Beads plan file created successfully", { planFilePath });
|
|
11397
|
-
} else {
|
|
11398
|
-
logger23.debug("Plan file already exists", { planFilePath });
|
|
11399
|
-
}
|
|
11400
|
-
}
|
|
11401
|
-
/**
|
|
11402
|
-
* Create initial plan file optimized for beads workflow
|
|
11403
|
-
*/
|
|
11404
|
-
async createInitialBeadsPlanFile(planFilePath, projectPath, gitBranch) {
|
|
11405
|
-
logger23.debug("Creating beads-optimized plan file", { planFilePath });
|
|
11406
|
-
try {
|
|
11407
|
-
await mkdir4(dirname6(planFilePath), { recursive: true });
|
|
11408
|
-
logger23.debug("Plan file directory ensured", {
|
|
11409
|
-
directory: dirname6(planFilePath)
|
|
11410
|
-
});
|
|
11411
|
-
const projectName = getPathBasename(projectPath, "Unknown Project");
|
|
11412
|
-
const branchInfo = gitBranch !== "no-git" ? ` (${gitBranch} branch)` : "";
|
|
11413
|
-
const initialContent = this.generateBeadsInitialPlanContent(
|
|
11414
|
-
projectName,
|
|
11415
|
-
branchInfo
|
|
11416
|
-
);
|
|
11417
|
-
await writeFile4(planFilePath, initialContent, "utf-8");
|
|
11418
|
-
logger23.info("Beads plan file written successfully", {
|
|
11419
|
-
planFilePath,
|
|
11420
|
-
contentLength: initialContent.length,
|
|
11421
|
-
projectName
|
|
11422
|
-
});
|
|
11423
|
-
} catch (error) {
|
|
11424
|
-
logger23.error("Failed to create beads plan file", error, {
|
|
11425
|
-
planFilePath
|
|
11426
|
-
});
|
|
11427
|
-
throw error;
|
|
11428
|
-
}
|
|
11429
|
-
}
|
|
11430
|
-
/**
|
|
11431
|
-
* Generate initial plan file content optimized for beads workflow
|
|
11432
|
-
*/
|
|
11433
|
-
generateBeadsInitialPlanContent(projectName, branchInfo) {
|
|
11434
|
-
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
11435
|
-
if (!this.stateMachine) {
|
|
11436
|
-
throw new Error(
|
|
11437
|
-
"State machine not set. This should not happen as state machine is always loaded."
|
|
11438
|
-
);
|
|
11439
|
-
}
|
|
11440
|
-
const phases = Object.keys(this.stateMachine.states);
|
|
11441
|
-
const initialPhase = this.stateMachine.initial_state;
|
|
11442
|
-
const documentationUrl = this.generateWorkflowDocumentationUrl(
|
|
11443
|
-
this.stateMachine.name
|
|
11444
|
-
);
|
|
11445
|
-
let content = `# Development Plan: ${projectName}${branchInfo}
|
|
11446
|
-
|
|
11447
|
-
*Generated on ${timestamp2} by Vibe Feature MCP*
|
|
11448
|
-
*Workflow: ${documentationUrl ? "[" + this.stateMachine.name + "](" + documentationUrl + ")" : this.stateMachine.name}*
|
|
11449
|
-
|
|
11450
|
-
## Goal
|
|
11451
|
-
*Define what you're building or fixing - this will be updated as requirements are gathered*
|
|
11452
|
-
|
|
11453
|
-
## ${this.capitalizePhase(initialPhase)}
|
|
11454
|
-
<!-- beads-phase-id: TBD -->
|
|
11455
|
-
### Tasks
|
|
11456
|
-
|
|
11457
|
-
*Tasks managed via \`bd\` CLI*
|
|
11458
|
-
|
|
11459
|
-
`;
|
|
11460
|
-
for (const phase of phases) {
|
|
11461
|
-
if (phase !== initialPhase) {
|
|
11462
|
-
content += `## ${this.capitalizePhase(phase)}
|
|
11463
|
-
<!-- beads-phase-id: TBD -->
|
|
11464
|
-
### Tasks
|
|
11465
|
-
|
|
11466
|
-
*Tasks managed via \`bd\` CLI*
|
|
11467
|
-
|
|
11468
|
-
`;
|
|
11469
|
-
}
|
|
11470
|
-
}
|
|
11471
|
-
content += `## Key Decisions
|
|
11472
|
-
*Important decisions will be documented here as they are made*
|
|
11473
|
-
|
|
11474
|
-
## Notes
|
|
11475
|
-
*Additional context and observations*
|
|
11476
|
-
|
|
11477
|
-
---
|
|
11478
|
-
*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.*
|
|
11479
|
-
`;
|
|
11480
|
-
return content;
|
|
11481
|
-
}
|
|
11482
|
-
/**
|
|
11483
|
-
* Update plan file with new content
|
|
11484
|
-
*/
|
|
11485
|
-
async updatePlanFile(planFilePath, content) {
|
|
11486
|
-
await mkdir4(dirname6(planFilePath), { recursive: true });
|
|
11487
|
-
await writeFile4(planFilePath, content, "utf-8");
|
|
11488
|
-
}
|
|
11489
|
-
/**
|
|
11490
|
-
* Get plan file content for LLM context
|
|
11491
|
-
*/
|
|
11492
|
-
async getPlanFileContent(planFilePath) {
|
|
11493
|
-
const planInfo = await this.getPlanFileInfo(planFilePath);
|
|
11494
|
-
if (!planInfo.exists) {
|
|
11495
|
-
return "Plan file does not exist yet. It will be created when the LLM updates it.";
|
|
11496
|
-
}
|
|
11497
|
-
return planInfo.content || "";
|
|
11498
|
-
}
|
|
11499
|
-
/**
|
|
11500
|
-
* Generate phase-specific plan file guidance optimized for beads
|
|
11501
|
-
*/
|
|
11502
|
-
generatePlanFileGuidance(phase) {
|
|
11503
|
-
if (!this.stateMachine) {
|
|
11504
|
-
throw new Error(
|
|
11505
|
-
"State machine not set. This should not happen as state machine is always loaded."
|
|
11506
|
-
);
|
|
11507
|
-
}
|
|
11508
|
-
const phaseDefinition = this.stateMachine.states[phase];
|
|
11509
|
-
if (!phaseDefinition) {
|
|
11510
|
-
logger23.warn("Unknown phase for beads plan file guidance", { phase });
|
|
11511
|
-
return `Track key decisions and take notes in the plan file. Use bd CLI for all task management.`;
|
|
11512
|
-
}
|
|
11513
|
-
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.`;
|
|
11514
|
-
}
|
|
11515
|
-
/**
|
|
11516
|
-
* Delete plan file
|
|
11517
|
-
*/
|
|
11518
|
-
async deletePlanFile(planFilePath) {
|
|
11519
|
-
logger23.debug("Deleting beads plan file", { planFilePath });
|
|
11520
|
-
try {
|
|
11521
|
-
await access6(planFilePath);
|
|
11522
|
-
const { unlink: unlink2 } = await import("fs/promises");
|
|
11523
|
-
await unlink2(planFilePath);
|
|
11524
|
-
logger23.info("Beads plan file deleted successfully", { planFilePath });
|
|
11525
|
-
return true;
|
|
11526
|
-
} catch (error) {
|
|
11527
|
-
if (error.code === "ENOENT") {
|
|
11528
|
-
logger23.debug("Beads plan file does not exist, nothing to delete", {
|
|
11529
|
-
planFilePath
|
|
11530
|
-
});
|
|
11531
|
-
return true;
|
|
11532
|
-
}
|
|
11533
|
-
logger23.error("Failed to delete beads plan file", error, {
|
|
11534
|
-
planFilePath
|
|
11535
|
-
});
|
|
11536
|
-
throw error;
|
|
11537
|
-
}
|
|
11538
|
-
}
|
|
11539
|
-
/**
|
|
11540
|
-
* Ensure plan file is deleted (verify deletion)
|
|
11541
|
-
*/
|
|
11542
|
-
async ensurePlanFileDeleted(planFilePath) {
|
|
11543
|
-
logger23.debug("Ensuring beads plan file is deleted", { planFilePath });
|
|
11544
|
-
try {
|
|
11545
|
-
await access6(planFilePath);
|
|
11546
|
-
logger23.warn("Beads plan file still exists after deletion attempt", {
|
|
11547
|
-
planFilePath
|
|
11548
|
-
});
|
|
11549
|
-
return false;
|
|
11550
|
-
} catch (error) {
|
|
11551
|
-
if (error.code === "ENOENT") {
|
|
11552
|
-
logger23.debug("Beads plan file successfully deleted (does not exist)", {
|
|
11553
|
-
planFilePath
|
|
11554
|
-
});
|
|
11555
|
-
return true;
|
|
11556
|
-
}
|
|
11557
|
-
logger23.error("Error checking beads plan file deletion", error, {
|
|
11558
|
-
planFilePath
|
|
11559
|
-
});
|
|
11560
|
-
throw error;
|
|
11561
|
-
}
|
|
11562
|
-
}
|
|
11563
|
-
/**
|
|
11564
|
-
* Capitalize phase name for display
|
|
11565
|
-
*/
|
|
11566
|
-
capitalizePhase(phase) {
|
|
11567
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
11568
|
-
}
|
|
11569
|
-
/**
|
|
11570
|
-
* Generate workflow documentation URL for predefined workflows
|
|
11571
|
-
*/
|
|
11572
|
-
generateWorkflowDocumentationUrl(workflowName) {
|
|
11573
|
-
if (workflowName === "custom") {
|
|
11574
|
-
return void 0;
|
|
11575
|
-
}
|
|
11576
|
-
return `https://mrsimpson.github.io/responsible-vibe-mcp/workflows/${workflowName}`;
|
|
11577
|
-
}
|
|
11578
|
-
};
|
|
11579
|
-
var BeadsInstructionGenerator = class {
|
|
11580
|
-
projectDocsManager;
|
|
11581
|
-
constructor() {
|
|
11582
|
-
this.projectDocsManager = new ProjectDocsManager();
|
|
11583
|
-
}
|
|
11584
|
-
/**
|
|
11585
|
-
* Set the state machine definition (interface requirement)
|
|
11586
|
-
*/
|
|
11587
|
-
setStateMachine(_stateMachine) {
|
|
11588
|
-
}
|
|
11589
|
-
/**
|
|
11590
|
-
* Generate comprehensive instructions optimized for beads workflow
|
|
11591
|
-
*/
|
|
11592
|
-
async generateInstructions(baseInstructions, context) {
|
|
11593
|
-
const substitutedInstructions = this.applyVariableSubstitution(
|
|
11594
|
-
baseInstructions,
|
|
11595
|
-
context.conversationContext.projectPath,
|
|
11596
|
-
context.conversationContext.gitBranch
|
|
11597
|
-
);
|
|
11598
|
-
const enhancedInstructions = await this.enhanceBeadsInstructions(
|
|
11599
|
-
substitutedInstructions,
|
|
11600
|
-
context
|
|
11601
|
-
);
|
|
11602
|
-
return {
|
|
11603
|
-
instructions: enhancedInstructions,
|
|
11604
|
-
planFileGuidance: "Using beads CLI for task management - plan file serves as context only",
|
|
11605
|
-
metadata: {
|
|
11606
|
-
phase: context.phase,
|
|
11607
|
-
planFilePath: context.conversationContext.planFilePath,
|
|
11608
|
-
transitionReason: context.transitionReason,
|
|
11609
|
-
isModeled: context.isModeled
|
|
11610
|
-
}
|
|
11611
|
-
};
|
|
11612
|
-
}
|
|
11613
|
-
/**
|
|
11614
|
-
* Apply variable substitution to instructions
|
|
11615
|
-
*/
|
|
11616
|
-
applyVariableSubstitution(instructions, projectPath, gitBranch) {
|
|
11617
|
-
const substitutions = this.projectDocsManager.getVariableSubstitutions(
|
|
11618
|
-
projectPath,
|
|
11619
|
-
gitBranch
|
|
11620
|
-
);
|
|
11621
|
-
let result = instructions;
|
|
11622
|
-
for (const [variable, value] of Object.entries(substitutions)) {
|
|
11623
|
-
result = result.replace(
|
|
11624
|
-
new RegExp(this.escapeRegExp(variable), "g"),
|
|
11625
|
-
value
|
|
11626
|
-
);
|
|
11627
|
-
}
|
|
11628
|
-
return result;
|
|
11629
|
-
}
|
|
11630
|
-
/**
|
|
11631
|
-
* Escape special regex characters in variable names
|
|
11632
|
-
*/
|
|
11633
|
-
escapeRegExp(string) {
|
|
11634
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11635
|
-
}
|
|
11636
|
-
/**
|
|
11637
|
-
* Enhance instructions with beads-specific guidance
|
|
11638
|
-
*/
|
|
11639
|
-
async enhanceBeadsInstructions(baseInstructions, context) {
|
|
11640
|
-
const { planFileExists } = context;
|
|
11641
|
-
const beadsTaskGuidance = await this.generateBeadsCLIGuidance(context);
|
|
11642
|
-
let enhanced = `${baseInstructions}
|
|
11643
|
-
|
|
11644
|
-
**Plan File Guidance:**
|
|
11645
|
-
Use the plan file as memory for the current objective
|
|
11646
|
-
- Update the "Key Decisions" section with important choices made
|
|
11647
|
-
- Add relevant notes to help maintain context
|
|
11648
|
-
- Do NOT enter tasks in the plan file, use beads CLI exclusively for task management
|
|
11649
|
-
|
|
11650
|
-
${beadsTaskGuidance}`;
|
|
11651
|
-
if (!planFileExists) {
|
|
11652
|
-
enhanced += "\n\n**Note**: Plan file will be created when you first update it.";
|
|
11653
|
-
}
|
|
11654
|
-
enhanced += `
|
|
11655
|
-
|
|
11656
|
-
**Important Reminders:**
|
|
11657
|
-
- Use ONLY bd CLI tool for task management - do not use your own task management tools
|
|
11658
|
-
- Call whats_next() after the next user message to maintain the development workflow`;
|
|
11659
|
-
return enhanced;
|
|
11660
|
-
}
|
|
11661
|
-
/**
|
|
11662
|
-
* Generate beads-specific task management guidance
|
|
11663
|
-
*/
|
|
11664
|
-
async generateBeadsCLIGuidance(context) {
|
|
11665
|
-
const { instructionSource } = context;
|
|
11666
|
-
if (instructionSource === "whats_next") {
|
|
11667
|
-
let additionalInstructions = `**bd Task Management:**
|
|
11668
|
-
`;
|
|
11669
|
-
const phaseTaskId = await this.extractPhaseTaskId(context);
|
|
11670
|
-
if (!phaseTaskId) {
|
|
11671
|
-
return additionalInstructions + `- Use bd CLI tool exclusively
|
|
11672
|
-
- **Start by listing ready tasks**: \`bd list --parent <phase-task-id> --status open\`
|
|
11673
|
-
- **Create new tasks**: \`bd create 'Task title' --parent <phase-task-id> -p <priority>\`
|
|
11674
|
-
- **Update status when working**: \`bd update <task-id> --status in_progress\`
|
|
11675
|
-
- **Complete tasks**: \`bd close <task-id>\`
|
|
11676
|
-
- **Focus on ready tasks first** - let beads handle dependencies
|
|
11677
|
-
- Add new tasks as they are identified during your work with the user`;
|
|
11678
|
-
}
|
|
11679
|
-
return additionalInstructions + `
|
|
11680
|
-
**Focus on subtasks of \`${phaseTaskId}\`**:
|
|
11681
|
-
\u2022 \`bd list --parent ${phaseTaskId} --status open\` - List ready work items
|
|
11682
|
-
\u2022 \`bd update <task-id> --status in_progress\` - Start working on a specific task
|
|
11683
|
-
\u2022 \`bd close <task-id>\` - Mark task complete when finished
|
|
11684
|
-
|
|
11685
|
-
**New Tasks for Current Phase**:
|
|
11686
|
-
\u2022 \`bd create 'Task description' --parent ${phaseTaskId} -p <priority>\` - Create work item under current phase
|
|
11687
|
-
\u2022 \`bd dep add <task-id> <depends-on-id>\` - Define dependencies for a task:`;
|
|
11688
|
-
}
|
|
11689
|
-
return "";
|
|
11690
|
-
}
|
|
11691
|
-
async extractPhaseTaskId(context) {
|
|
11692
|
-
try {
|
|
11693
|
-
const { readFile: readFile6 } = await import("fs/promises");
|
|
11694
|
-
const content = await readFile6(
|
|
11695
|
-
context.conversationContext.planFilePath,
|
|
11696
|
-
"utf-8"
|
|
11697
|
-
);
|
|
11698
|
-
const phaseName = this.capitalizePhase(context.phase);
|
|
11699
|
-
const phaseHeader = `## ${phaseName}`;
|
|
11700
|
-
const phaseSection = content.split("\n");
|
|
11701
|
-
let foundPhaseHeader = false;
|
|
11702
|
-
for (const line of phaseSection) {
|
|
11703
|
-
if (line.trim() === phaseHeader) {
|
|
11704
|
-
foundPhaseHeader = true;
|
|
11705
|
-
continue;
|
|
11706
|
-
}
|
|
11707
|
-
if (foundPhaseHeader && line.includes("beads-phase-id:")) {
|
|
11708
|
-
const match = line.match(/beads-phase-id:\s*([\w\d.-]+)/);
|
|
11709
|
-
if (match) {
|
|
11710
|
-
return match[1] || null;
|
|
11711
|
-
}
|
|
11712
|
-
}
|
|
11713
|
-
if (foundPhaseHeader && line.startsWith("##") && line !== phaseHeader) {
|
|
11714
|
-
break;
|
|
11715
|
-
}
|
|
11716
|
-
}
|
|
11717
|
-
return null;
|
|
11718
|
-
} catch (_error) {
|
|
11719
|
-
return null;
|
|
11720
|
-
}
|
|
11721
|
-
}
|
|
11722
|
-
/**
|
|
11723
|
-
* Capitalize phase name for display
|
|
11724
|
-
*/
|
|
11725
|
-
capitalizePhase(phase) {
|
|
11726
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
11727
|
-
}
|
|
11728
|
-
};
|
|
11729
|
-
var logger24 = createLogger("ServerConfig");
|
|
11406
|
+
var logger15 = createLogger("ServerConfig");
|
|
11730
11407
|
async function initializeServerComponents(config = {}) {
|
|
11731
|
-
|
|
11408
|
+
logger15.debug("Initializing server components", {
|
|
11732
11409
|
config: JSON.stringify(config)
|
|
11733
11410
|
});
|
|
11734
11411
|
const projectPath = normalizeProjectPath(
|
|
11735
11412
|
config.projectPath || process.env.PROJECT_PATH
|
|
11736
11413
|
);
|
|
11737
|
-
|
|
11414
|
+
logger15.info("Using project path", {
|
|
11738
11415
|
projectPath,
|
|
11739
11416
|
source: config.projectPath ? "config" : process.env.PROJECT_PATH ? "env" : "default"
|
|
11740
11417
|
});
|
|
@@ -11751,11 +11428,11 @@ async function initializeServerComponents(config = {}) {
|
|
|
11751
11428
|
);
|
|
11752
11429
|
mcpServer.server.setRequestHandler(SetLevelRequestSchema, async (request) => {
|
|
11753
11430
|
const level = request.params.level;
|
|
11754
|
-
|
|
11755
|
-
|
|
11431
|
+
logger15.info("Setting logging level from MCP client", { level });
|
|
11432
|
+
setLoggingLevelFromString(level);
|
|
11756
11433
|
return {};
|
|
11757
11434
|
});
|
|
11758
|
-
|
|
11435
|
+
logger15.debug("Initializing core components");
|
|
11759
11436
|
const database = new FileStorage(
|
|
11760
11437
|
path4.join(projectPath, ".vibe", "conversation.sqlite")
|
|
11761
11438
|
);
|
|
@@ -11768,38 +11445,31 @@ async function initializeServerComponents(config = {}) {
|
|
|
11768
11445
|
const transitionEngine = new TransitionEngine(projectPath);
|
|
11769
11446
|
transitionEngine.setConversationManager(conversationManager);
|
|
11770
11447
|
const taskBackendConfig = TaskBackendManager.detectTaskBackend();
|
|
11771
|
-
|
|
11772
|
-
logger24.info("Task backend configuration", {
|
|
11448
|
+
logger15.info("Task backend configuration", {
|
|
11773
11449
|
backend: taskBackendConfig.backend,
|
|
11774
11450
|
isAvailable: taskBackendConfig.isAvailable,
|
|
11775
11451
|
autoDetected: !process.env["TASK_BACKEND"]
|
|
11776
11452
|
});
|
|
11777
|
-
const planManager =
|
|
11778
|
-
const instructionGenerator =
|
|
11453
|
+
const planManager = new PlanManager();
|
|
11454
|
+
const instructionGenerator = new InstructionGenerator();
|
|
11779
11455
|
const interactionLogger = new InteractionLogger(database);
|
|
11780
11456
|
const pluginRegistry = new PluginRegistry();
|
|
11781
|
-
|
|
11782
|
-
|
|
11783
|
-
|
|
11784
|
-
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
|
|
11788
|
-
|
|
11789
|
-
|
|
11790
|
-
|
|
11791
|
-
|
|
11792
|
-
|
|
11793
|
-
|
|
11794
|
-
|
|
11795
|
-
|
|
11796
|
-
|
|
11797
|
-
enabled: beadsPlugin.isEnabled(),
|
|
11798
|
-
sequence: beadsPlugin.getSequence(),
|
|
11799
|
-
autoDetected: !process.env["TASK_BACKEND"]
|
|
11800
|
-
});
|
|
11801
|
-
}
|
|
11802
|
-
}
|
|
11457
|
+
const commitPlugin = new CommitPlugin({ projectPath });
|
|
11458
|
+
pluginRegistry.registerPlugin(commitPlugin);
|
|
11459
|
+
logger15.info("CommitPlugin registered", {
|
|
11460
|
+
enabled: commitPlugin.isEnabled(),
|
|
11461
|
+
sequence: commitPlugin.getSequence(),
|
|
11462
|
+
behavior: process.env.COMMIT_BEHAVIOR || "(not set)"
|
|
11463
|
+
});
|
|
11464
|
+
const beadsPlugin = new BeadsPlugin({ projectPath });
|
|
11465
|
+
pluginRegistry.registerPlugin(beadsPlugin);
|
|
11466
|
+
logger15.info("BeadsPlugin registered", {
|
|
11467
|
+
enabled: beadsPlugin.isEnabled(),
|
|
11468
|
+
sequence: beadsPlugin.getSequence(),
|
|
11469
|
+
backend: taskBackendConfig.backend,
|
|
11470
|
+
isAvailable: taskBackendConfig.isAvailable,
|
|
11471
|
+
autoDetected: !process.env["TASK_BACKEND"]
|
|
11472
|
+
});
|
|
11803
11473
|
const context = {
|
|
11804
11474
|
conversationManager,
|
|
11805
11475
|
transitionEngine,
|
|
@@ -11812,7 +11482,7 @@ async function initializeServerComponents(config = {}) {
|
|
|
11812
11482
|
};
|
|
11813
11483
|
await database.initialize();
|
|
11814
11484
|
workflowManager.loadProjectWorkflows(projectPath);
|
|
11815
|
-
|
|
11485
|
+
logger15.info("Server components initialized successfully");
|
|
11816
11486
|
return {
|
|
11817
11487
|
mcpServer,
|
|
11818
11488
|
database,
|
|
@@ -11835,7 +11505,7 @@ function createToolHandler(toolName, toolRegistry, responseRenderer, context) {
|
|
|
11835
11505
|
};
|
|
11836
11506
|
}
|
|
11837
11507
|
async function registerMcpTools(mcpServer, toolRegistry, responseRenderer, context) {
|
|
11838
|
-
|
|
11508
|
+
logger15.debug("Registering MCP tools");
|
|
11839
11509
|
notificationService.setMcpServer(mcpServer);
|
|
11840
11510
|
mcpServer.registerTool(
|
|
11841
11511
|
"whats_next",
|
|
@@ -12035,7 +11705,7 @@ async function registerMcpTools(mcpServer, toolRegistry, responseRenderer, conte
|
|
|
12035
11705
|
mcpServer.registerTool(
|
|
12036
11706
|
"setup_project_docs",
|
|
12037
11707
|
{
|
|
12038
|
-
description:
|
|
11708
|
+
description: "Create or link project docs (architecture.md, requirements.md, design.md). Use template names or file paths.",
|
|
12039
11709
|
inputSchema: {
|
|
12040
11710
|
architecture: external_exports.string().default("freestyle").describe(
|
|
12041
11711
|
`Architecture documentation: template name (${availableTemplates.architecture.join(", ")}, none) OR file path to existing document`
|
|
@@ -12082,12 +11752,12 @@ async function registerMcpTools(mcpServer, toolRegistry, responseRenderer, conte
|
|
|
12082
11752
|
},
|
|
12083
11753
|
createToolHandler("no_idea", toolRegistry, responseRenderer, context)
|
|
12084
11754
|
);
|
|
12085
|
-
|
|
11755
|
+
logger15.info("MCP tools registered successfully", {
|
|
12086
11756
|
tools: toolRegistry.list()
|
|
12087
11757
|
});
|
|
12088
11758
|
}
|
|
12089
11759
|
function registerMcpResources(mcpServer, resourceRegistry, responseRenderer, context) {
|
|
12090
|
-
|
|
11760
|
+
logger15.debug("Registering MCP resources");
|
|
12091
11761
|
mcpServer.resource(
|
|
12092
11762
|
"Current Development Plan",
|
|
12093
11763
|
"plan://current",
|
|
@@ -12220,7 +11890,7 @@ function registerMcpResources(mcpServer, resourceRegistry, responseRenderer, con
|
|
|
12220
11890
|
};
|
|
12221
11891
|
}
|
|
12222
11892
|
);
|
|
12223
|
-
|
|
11893
|
+
logger15.info("MCP resources registered successfully", {
|
|
12224
11894
|
resources: ["plan://current", "state://current", "system-prompt://"],
|
|
12225
11895
|
resourceTemplates: ["workflow://{name}"]
|
|
12226
11896
|
});
|
|
@@ -12235,18 +11905,22 @@ var BaseToolHandler = class {
|
|
|
12235
11905
|
*/
|
|
12236
11906
|
async handle(args, context) {
|
|
12237
11907
|
const handlerName = this.constructor.name;
|
|
12238
|
-
|
|
11908
|
+
if (context.loggerFactory) {
|
|
11909
|
+
this.logger = context.loggerFactory(handlerName);
|
|
11910
|
+
}
|
|
11911
|
+
logHandlerExecution(handlerName, args, this.logger);
|
|
12239
11912
|
const result = await safeExecute(
|
|
12240
11913
|
() => this.executeHandler(args, context),
|
|
12241
|
-
`${handlerName} execution failed
|
|
11914
|
+
`${handlerName} execution failed`,
|
|
11915
|
+
this.logger
|
|
12242
11916
|
);
|
|
12243
11917
|
if (!result.success && result.error?.includes("CONVERSATION_NOT_FOUND")) {
|
|
12244
11918
|
const availableWorkflows = context.workflowManager.getWorkflowNames();
|
|
12245
11919
|
const helpfulError = createConversationNotFoundResult(availableWorkflows);
|
|
12246
|
-
logHandlerCompletion(handlerName, helpfulError);
|
|
11920
|
+
logHandlerCompletion(handlerName, helpfulError, this.logger);
|
|
12247
11921
|
return helpfulError;
|
|
12248
11922
|
}
|
|
12249
|
-
logHandlerCompletion(handlerName, result);
|
|
11923
|
+
logHandlerCompletion(handlerName, result, this.logger);
|
|
12250
11924
|
return result;
|
|
12251
11925
|
}
|
|
12252
11926
|
/**
|
|
@@ -12380,6 +12054,12 @@ var WhatsNextHandler = class extends ConversationRequiredToolHandler {
|
|
|
12380
12054
|
const planInfo = await context.planManager.getPlanFileInfo(
|
|
12381
12055
|
conversationContext.planFilePath
|
|
12382
12056
|
);
|
|
12057
|
+
const stateMachine = context.workflowManager.loadWorkflowForProject(
|
|
12058
|
+
conversationContext.projectPath,
|
|
12059
|
+
conversationContext.workflowName
|
|
12060
|
+
);
|
|
12061
|
+
const phaseState = stateMachine.states[transitionResult.newPhase];
|
|
12062
|
+
const allowedFilePatterns = phaseState?.allowed_file_patterns ?? ["**/*"];
|
|
12383
12063
|
const instructions = await context.instructionGenerator.generateInstructions(
|
|
12384
12064
|
transitionResult.instructions,
|
|
12385
12065
|
{
|
|
@@ -12390,14 +12070,40 @@ var WhatsNextHandler = class extends ConversationRequiredToolHandler {
|
|
|
12390
12070
|
},
|
|
12391
12071
|
transitionReason: transitionResult.transitionReason,
|
|
12392
12072
|
isModeled: transitionResult.isModeled,
|
|
12393
|
-
|
|
12394
|
-
|
|
12073
|
+
instructionSource: "whats_next",
|
|
12074
|
+
allowedFilePatterns
|
|
12395
12075
|
}
|
|
12396
12076
|
);
|
|
12077
|
+
let finalInstructions = instructions.instructions;
|
|
12078
|
+
if (context.pluginRegistry?.hasHook("afterInstructionsGenerated")) {
|
|
12079
|
+
const hookContext = {
|
|
12080
|
+
conversationId,
|
|
12081
|
+
planFilePath: conversationContext.planFilePath,
|
|
12082
|
+
currentPhase: transitionResult.newPhase,
|
|
12083
|
+
workflow: conversationContext.workflowName,
|
|
12084
|
+
projectPath: conversationContext.projectPath,
|
|
12085
|
+
gitBranch: conversationContext.gitBranch,
|
|
12086
|
+
planFileExists: planInfo.exists
|
|
12087
|
+
};
|
|
12088
|
+
const enriched = await context.pluginRegistry.executeHook(
|
|
12089
|
+
"afterInstructionsGenerated",
|
|
12090
|
+
hookContext,
|
|
12091
|
+
{
|
|
12092
|
+
instructions: instructions.instructions,
|
|
12093
|
+
planFilePath: conversationContext.planFilePath,
|
|
12094
|
+
phase: transitionResult.newPhase,
|
|
12095
|
+
instructionSource: "whats_next"
|
|
12096
|
+
}
|
|
12097
|
+
);
|
|
12098
|
+
if (enriched && typeof enriched === "object" && "instructions" in enriched) {
|
|
12099
|
+
finalInstructions = enriched.instructions;
|
|
12100
|
+
}
|
|
12101
|
+
}
|
|
12397
12102
|
const response = {
|
|
12398
12103
|
phase: transitionResult.newPhase,
|
|
12399
|
-
instructions:
|
|
12400
|
-
plan_file_path: conversationContext.planFilePath
|
|
12104
|
+
instructions: finalInstructions,
|
|
12105
|
+
plan_file_path: conversationContext.planFilePath,
|
|
12106
|
+
allowed_file_patterns: allowedFilePatterns
|
|
12401
12107
|
};
|
|
12402
12108
|
await this.logInteraction(
|
|
12403
12109
|
context,
|
|
@@ -12442,8 +12148,6 @@ var WhatsNextHandler = class extends ConversationRequiredToolHandler {
|
|
|
12442
12148
|
}
|
|
12443
12149
|
return true;
|
|
12444
12150
|
}
|
|
12445
|
-
// Beads-specific instruction logic has been moved to BeadsInstructionGenerator strategy
|
|
12446
|
-
// Utility methods moved to strategy implementations where needed
|
|
12447
12151
|
};
|
|
12448
12152
|
var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
12449
12153
|
async executeWithConversation(args, context, conversationContext) {
|
|
@@ -12475,6 +12179,9 @@ var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
|
12475
12179
|
conversationContext.projectPath,
|
|
12476
12180
|
context
|
|
12477
12181
|
);
|
|
12182
|
+
const prePlanInfo = await context.planManager.getPlanFileInfo(
|
|
12183
|
+
conversationContext.planFilePath
|
|
12184
|
+
);
|
|
12478
12185
|
const pluginContext = {
|
|
12479
12186
|
conversationId,
|
|
12480
12187
|
planFilePath: conversationContext.planFilePath,
|
|
@@ -12482,6 +12189,7 @@ var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
|
12482
12189
|
workflow: conversationContext.workflowName,
|
|
12483
12190
|
projectPath: conversationContext.projectPath,
|
|
12484
12191
|
gitBranch: conversationContext.gitBranch,
|
|
12192
|
+
planFileExists: prePlanInfo.exists,
|
|
12485
12193
|
targetPhase: target_phase
|
|
12486
12194
|
};
|
|
12487
12195
|
if (context.pluginRegistry) {
|
|
@@ -12516,6 +12224,12 @@ var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
|
12516
12224
|
const planInfo = await context.planManager.getPlanFileInfo(
|
|
12517
12225
|
conversationContext.planFilePath
|
|
12518
12226
|
);
|
|
12227
|
+
const stateMachine = context.workflowManager.loadWorkflowForProject(
|
|
12228
|
+
conversationContext.projectPath,
|
|
12229
|
+
conversationContext.workflowName
|
|
12230
|
+
);
|
|
12231
|
+
const phaseState = stateMachine.states[transitionResult.newPhase];
|
|
12232
|
+
const allowedFilePatterns = phaseState?.allowed_file_patterns ?? ["**/*"];
|
|
12519
12233
|
const instructions = await context.instructionGenerator.generateInstructions(
|
|
12520
12234
|
transitionResult.instructions,
|
|
12521
12235
|
{
|
|
@@ -12526,20 +12240,42 @@ var ProceedToPhaseHandler = class extends ConversationRequiredToolHandler {
|
|
|
12526
12240
|
},
|
|
12527
12241
|
transitionReason: transitionResult.transitionReason,
|
|
12528
12242
|
isModeled: transitionResult.isModeled,
|
|
12529
|
-
|
|
12530
|
-
|
|
12243
|
+
instructionSource: "proceed_to_phase",
|
|
12244
|
+
allowedFilePatterns
|
|
12531
12245
|
}
|
|
12532
12246
|
);
|
|
12533
|
-
instructions.instructions
|
|
12534
|
-
|
|
12535
|
-
|
|
12536
|
-
|
|
12537
|
-
|
|
12247
|
+
let finalInstructions = instructions.instructions;
|
|
12248
|
+
if (context.pluginRegistry?.hasHook("afterInstructionsGenerated")) {
|
|
12249
|
+
const hookContext = {
|
|
12250
|
+
conversationId,
|
|
12251
|
+
planFilePath: conversationContext.planFilePath,
|
|
12252
|
+
currentPhase: transitionResult.newPhase,
|
|
12253
|
+
workflow: conversationContext.workflowName,
|
|
12254
|
+
projectPath: conversationContext.projectPath,
|
|
12255
|
+
gitBranch: conversationContext.gitBranch,
|
|
12256
|
+
planFileExists: planInfo.exists
|
|
12257
|
+
};
|
|
12258
|
+
const enriched = await context.pluginRegistry.executeHook(
|
|
12259
|
+
"afterInstructionsGenerated",
|
|
12260
|
+
hookContext,
|
|
12261
|
+
{
|
|
12262
|
+
instructions: instructions.instructions,
|
|
12263
|
+
planFilePath: conversationContext.planFilePath,
|
|
12264
|
+
phase: transitionResult.newPhase,
|
|
12265
|
+
instructionSource: "proceed_to_phase"
|
|
12266
|
+
}
|
|
12267
|
+
);
|
|
12268
|
+
if (enriched && typeof enriched === "object" && "instructions" in enriched) {
|
|
12269
|
+
finalInstructions = enriched.instructions;
|
|
12270
|
+
}
|
|
12271
|
+
}
|
|
12272
|
+
finalInstructions += ` Review tasks for ${transitionResult.newPhase} phase, add missing ones based on key decisions.`;
|
|
12538
12273
|
const response = {
|
|
12539
12274
|
phase: transitionResult.newPhase,
|
|
12540
|
-
instructions:
|
|
12275
|
+
instructions: finalInstructions,
|
|
12541
12276
|
plan_file_path: conversationContext.planFilePath,
|
|
12542
|
-
transition_reason: transitionResult.transitionReason
|
|
12277
|
+
transition_reason: transitionResult.transitionReason,
|
|
12278
|
+
allowed_file_patterns: allowedFilePatterns
|
|
12543
12279
|
};
|
|
12544
12280
|
await this.logInteraction(
|
|
12545
12281
|
context,
|
|
@@ -12704,23 +12440,17 @@ var ConductReviewHandler = class extends ConversationRequiredToolHandler {
|
|
|
12704
12440
|
* Generate instructions for LLM to conduct guided review
|
|
12705
12441
|
*/
|
|
12706
12442
|
async generateReviewInstructions(perspectives, currentPhase, targetPhase) {
|
|
12707
|
-
const
|
|
12708
|
-
|
|
12709
|
-
|
|
12710
|
-
|
|
12711
|
-
2. Using git status/diff to see what files were changed (if in a git repository)
|
|
12712
|
-
3. Analyzing recent conversation history for important decisions
|
|
12443
|
+
const perspectiveDetails = perspectives.map(
|
|
12444
|
+
(p, i2) => `${i2 + 1}. **${p.perspective.toUpperCase()}**: ${p.prompt}`
|
|
12445
|
+
).join("\n");
|
|
12446
|
+
const instructions = `Review ${currentPhase} phase before proceeding to ${targetPhase}.
|
|
12713
12447
|
|
|
12714
|
-
|
|
12448
|
+
**Check:** plan file (tasks/decisions), git diff (changes), conversation history.
|
|
12715
12449
|
|
|
12716
|
-
|
|
12717
|
-
|
|
12718
|
-
${p.prompt}
|
|
12450
|
+
**Perspectives:**
|
|
12451
|
+
${perspectiveDetails}
|
|
12719
12452
|
|
|
12720
|
-
|
|
12721
|
-
).join("")}
|
|
12722
|
-
|
|
12723
|
-
After completing all perspective reviews, summarize your findings and ask the user if they're ready to proceed to the ${targetPhase} phase.`;
|
|
12453
|
+
Summarize findings and ask user if ready to proceed.`;
|
|
12724
12454
|
return {
|
|
12725
12455
|
instructions,
|
|
12726
12456
|
perspectives: perspectives.map((p) => ({
|
|
@@ -12730,16 +12460,19 @@ After completing all perspective reviews, summarize your findings and ask the us
|
|
|
12730
12460
|
};
|
|
12731
12461
|
}
|
|
12732
12462
|
};
|
|
12733
|
-
var logger25 = createLogger("StartDevelopmentHandler");
|
|
12734
12463
|
var StartDevelopmentHandler = class extends BaseToolHandler {
|
|
12735
|
-
projectDocsManager;
|
|
12736
|
-
|
|
12737
|
-
|
|
12738
|
-
|
|
12464
|
+
projectDocsManager = null;
|
|
12465
|
+
getProjectDocsManager() {
|
|
12466
|
+
if (!this.projectDocsManager) {
|
|
12467
|
+
this.projectDocsManager = new ProjectDocsManager(this.logger);
|
|
12468
|
+
}
|
|
12469
|
+
return this.projectDocsManager;
|
|
12739
12470
|
}
|
|
12740
12471
|
async executeHandler(args, context) {
|
|
12741
12472
|
validateRequiredArgs(args, ["workflow"]);
|
|
12742
|
-
const taskBackendConfig = TaskBackendManager.validateTaskBackend(
|
|
12473
|
+
const taskBackendConfig = TaskBackendManager.validateTaskBackend(
|
|
12474
|
+
this.logger
|
|
12475
|
+
);
|
|
12743
12476
|
const selectedWorkflow = args.workflow;
|
|
12744
12477
|
const requireReviews = args.require_reviews ?? false;
|
|
12745
12478
|
const projectPath = stripVibePathSuffix(
|
|
@@ -12773,12 +12506,10 @@ var StartDevelopmentHandler = class extends BaseToolHandler {
|
|
|
12773
12506
|
const suggestedBranchName = this.generateBranchSuggestion();
|
|
12774
12507
|
const branchPromptResponse = {
|
|
12775
12508
|
phase: "branch-prompt",
|
|
12776
|
-
instructions: `
|
|
12777
|
-
|
|
12778
|
-
|
|
12779
|
-
|
|
12780
|
-
Please create a new branch and then call start_development again to begin development.`,
|
|
12781
|
-
plan_file_path: ""
|
|
12509
|
+
instructions: `On ${currentBranch}. Create feature branch: \`git checkout -b ${suggestedBranchName}\`, then retry \`start_development\`.`,
|
|
12510
|
+
plan_file_path: "",
|
|
12511
|
+
allowed_file_patterns: ["**/*"]
|
|
12512
|
+
// Allow all files during branch prompt
|
|
12782
12513
|
};
|
|
12783
12514
|
this.logger.debug(
|
|
12784
12515
|
"User on main/master branch, prompting for branch creation",
|
|
@@ -12836,6 +12567,8 @@ Please create a new branch and then call start_development again to begin develo
|
|
|
12836
12567
|
workflow: selectedWorkflow,
|
|
12837
12568
|
projectPath,
|
|
12838
12569
|
gitBranch: conversationContext.gitBranch,
|
|
12570
|
+
planFileExists: true,
|
|
12571
|
+
// we just created/ensured the plan file exists
|
|
12839
12572
|
stateMachine: {
|
|
12840
12573
|
name: stateMachine.name,
|
|
12841
12574
|
description: stateMachine.description,
|
|
@@ -12845,7 +12578,7 @@ Please create a new branch and then call start_development again to begin develo
|
|
|
12845
12578
|
};
|
|
12846
12579
|
if (context.pluginRegistry) {
|
|
12847
12580
|
try {
|
|
12848
|
-
const originalContent = await
|
|
12581
|
+
const originalContent = await readFile4(
|
|
12849
12582
|
conversationContext.planFilePath,
|
|
12850
12583
|
"utf-8"
|
|
12851
12584
|
);
|
|
@@ -12856,14 +12589,14 @@ Please create a new branch and then call start_development again to begin develo
|
|
|
12856
12589
|
originalContent
|
|
12857
12590
|
);
|
|
12858
12591
|
if (modifiedContent && modifiedContent !== originalContent) {
|
|
12859
|
-
await
|
|
12592
|
+
await writeFile4(
|
|
12860
12593
|
conversationContext.planFilePath,
|
|
12861
12594
|
modifiedContent,
|
|
12862
12595
|
"utf-8"
|
|
12863
12596
|
);
|
|
12864
12597
|
}
|
|
12865
12598
|
} catch (error) {
|
|
12866
|
-
|
|
12599
|
+
this.logger.debug("Could not execute afterPlanFileCreated hook", {
|
|
12867
12600
|
error: error instanceof Error ? error.message : String(error),
|
|
12868
12601
|
planFilePath: conversationContext.planFilePath
|
|
12869
12602
|
});
|
|
@@ -12888,30 +12621,33 @@ Please create a new branch and then call start_development again to begin develo
|
|
|
12888
12621
|
}
|
|
12889
12622
|
this.ensureGitignoreEntry(projectPath);
|
|
12890
12623
|
const workflowDocumentationUrl = this.generateWorkflowDocumentationUrl(selectedWorkflow);
|
|
12891
|
-
|
|
12892
|
-
|
|
12893
|
-
|
|
12894
|
-
|
|
12895
|
-
|
|
12896
|
-
|
|
12897
|
-
|
|
12898
|
-
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
|
|
12902
|
-
|
|
12903
|
-
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
|
|
12907
|
-
|
|
12908
|
-
|
|
12909
|
-
|
|
12624
|
+
let finalInstructions = context.planManager.getInitialPlanGuidance(
|
|
12625
|
+
conversationContext.planFilePath,
|
|
12626
|
+
workflowDocumentationUrl
|
|
12627
|
+
);
|
|
12628
|
+
const phaseState = stateMachine.states[transitionResult.newPhase];
|
|
12629
|
+
const allowedFilePatterns = phaseState?.allowed_file_patterns ?? ["**/*"];
|
|
12630
|
+
if (context.pluginRegistry?.hasHook("afterInstructionsGenerated")) {
|
|
12631
|
+
const enriched = await context.pluginRegistry.executeHook(
|
|
12632
|
+
"afterInstructionsGenerated",
|
|
12633
|
+
pluginContext,
|
|
12634
|
+
{
|
|
12635
|
+
instructions: finalInstructions,
|
|
12636
|
+
planFilePath: conversationContext.planFilePath,
|
|
12637
|
+
phase: transitionResult.newPhase,
|
|
12638
|
+
instructionSource: "start_development"
|
|
12639
|
+
}
|
|
12640
|
+
);
|
|
12641
|
+
if (enriched && typeof enriched === "object" && "instructions" in enriched) {
|
|
12642
|
+
finalInstructions = enriched.instructions;
|
|
12643
|
+
}
|
|
12644
|
+
}
|
|
12910
12645
|
const response = {
|
|
12911
12646
|
phase: transitionResult.newPhase,
|
|
12912
12647
|
instructions: finalInstructions,
|
|
12913
12648
|
plan_file_path: conversationContext.planFilePath,
|
|
12914
|
-
workflowDocumentationUrl
|
|
12649
|
+
workflowDocumentationUrl,
|
|
12650
|
+
allowed_file_patterns: allowedFilePatterns
|
|
12915
12651
|
};
|
|
12916
12652
|
await this.logInteraction(
|
|
12917
12653
|
context,
|
|
@@ -12953,7 +12689,7 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
12953
12689
|
);
|
|
12954
12690
|
return null;
|
|
12955
12691
|
}
|
|
12956
|
-
const docsInfo = await this.
|
|
12692
|
+
const docsInfo = await this.getProjectDocsManager().getProjectDocsInfo(projectPath);
|
|
12957
12693
|
const missingDocs = this.getMissingReferencedDocuments(
|
|
12958
12694
|
referencedVariables,
|
|
12959
12695
|
docsInfo,
|
|
@@ -12971,9 +12707,7 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
12971
12707
|
}
|
|
12972
12708
|
const setupGuidance = await this.generateArtifactSetupGuidance(
|
|
12973
12709
|
missingDocs,
|
|
12974
|
-
workflowName
|
|
12975
|
-
docsInfo,
|
|
12976
|
-
referencedVariables
|
|
12710
|
+
workflowName
|
|
12977
12711
|
);
|
|
12978
12712
|
this.logger.info(
|
|
12979
12713
|
"Missing required project artifacts detected for workflow that requires documentation",
|
|
@@ -12985,10 +12719,17 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
12985
12719
|
projectPath
|
|
12986
12720
|
}
|
|
12987
12721
|
);
|
|
12722
|
+
const initialPhase = stateMachine.initial_state;
|
|
12723
|
+
const initialPhaseState = stateMachine.states[initialPhase];
|
|
12724
|
+
const allowedFilePatterns = initialPhaseState?.allowed_file_patterns ?? [
|
|
12725
|
+
"**/*"
|
|
12726
|
+
];
|
|
12988
12727
|
return {
|
|
12989
12728
|
phase: "artifact-setup",
|
|
12990
12729
|
instructions: setupGuidance,
|
|
12991
|
-
plan_file_path: ""
|
|
12730
|
+
plan_file_path: "",
|
|
12731
|
+
// Use the initial phase's file restrictions during artifact setup
|
|
12732
|
+
allowed_file_patterns: allowedFilePatterns
|
|
12992
12733
|
};
|
|
12993
12734
|
} catch (error) {
|
|
12994
12735
|
this.logger.warn(
|
|
@@ -13005,7 +12746,7 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
13005
12746
|
* Analyze workflow content to detect document variable references
|
|
13006
12747
|
*/
|
|
13007
12748
|
analyzeWorkflowDocumentReferences(stateMachine, projectPath) {
|
|
13008
|
-
const variableSubstitutions = this.
|
|
12749
|
+
const variableSubstitutions = this.getProjectDocsManager().getVariableSubstitutions(projectPath);
|
|
13009
12750
|
const documentVariables = Object.keys(variableSubstitutions);
|
|
13010
12751
|
const referencedVariables = /* @__PURE__ */ new Set();
|
|
13011
12752
|
const workflowContent = JSON.stringify(stateMachine);
|
|
@@ -13026,7 +12767,10 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
13026
12767
|
*/
|
|
13027
12768
|
getMissingReferencedDocuments(referencedVariables, docsInfo, projectPath) {
|
|
13028
12769
|
const missingDocs = [];
|
|
13029
|
-
const variableSubstitutions = this.
|
|
12770
|
+
const variableSubstitutions = this.getProjectDocsManager().getVariableSubstitutions(
|
|
12771
|
+
projectPath,
|
|
12772
|
+
void 0
|
|
12773
|
+
);
|
|
13030
12774
|
const variableToDocMap = {};
|
|
13031
12775
|
for (const [variable, path6] of Object.entries(variableSubstitutions)) {
|
|
13032
12776
|
const filename = basename4(path6);
|
|
@@ -13047,115 +12791,15 @@ Inform the user about the chose workflow: He can visit: ${workflowDocumentationU
|
|
|
13047
12791
|
/**
|
|
13048
12792
|
* Generate guidance for setting up missing project artifacts
|
|
13049
12793
|
*/
|
|
13050
|
-
async generateArtifactSetupGuidance(missingDocs, workflowName
|
|
13051
|
-
const
|
|
13052
|
-
|
|
13053
|
-
if (docsInfo.architecture.exists) {
|
|
13054
|
-
const fileName = basename4(docsInfo.architecture.path);
|
|
13055
|
-
existingDocs.push(`\u2705 ${fileName}`);
|
|
13056
|
-
}
|
|
13057
|
-
if (docsInfo.requirements.exists) {
|
|
13058
|
-
const fileName = basename4(docsInfo.requirements.path);
|
|
13059
|
-
existingDocs.push(`\u2705 ${fileName}`);
|
|
13060
|
-
}
|
|
13061
|
-
if (docsInfo.design.exists) {
|
|
13062
|
-
const fileName = basename4(docsInfo.design.path);
|
|
13063
|
-
existingDocs.push(`\u2705 ${fileName}`);
|
|
13064
|
-
}
|
|
13065
|
-
const existingList = existingDocs.length > 0 ? `
|
|
13066
|
-
|
|
13067
|
-
**Existing Documents:**
|
|
13068
|
-
${existingDocs.join("\n")}` : "";
|
|
13069
|
-
const referencedVariablesList = referencedVariables.map((v) => `\`${v}\``).join(", ");
|
|
13070
|
-
const availableTemplates = await this.projectDocsManager.templateManager.getAvailableTemplates();
|
|
13071
|
-
const defaults = await this.projectDocsManager.templateManager.getDefaults();
|
|
13072
|
-
const templateOptionsText = this.generateTemplateOptionsText(availableTemplates);
|
|
13073
|
-
return `## Project Documentation Setup Required
|
|
12794
|
+
async generateArtifactSetupGuidance(missingDocs, workflowName) {
|
|
12795
|
+
const availableTemplates = await this.getProjectDocsManager().templateManager.getAvailableTemplates();
|
|
12796
|
+
return `Missing docs for **${workflowName}**: ${missingDocs.join(", ")}
|
|
13074
12797
|
|
|
13075
|
-
|
|
12798
|
+
Run \`setup_project_docs()\` with templates: ${Object.entries(
|
|
12799
|
+
availableTemplates
|
|
12800
|
+
).map(([type2, templates]) => `${type2}: ${templates.join("/")}`).join("; ")}
|
|
13076
12801
|
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
**Missing Documents:**
|
|
13080
|
-
${missingList}${existingList}
|
|
13081
|
-
|
|
13082
|
-
## \u{1F680} **Quick Setup**
|
|
13083
|
-
|
|
13084
|
-
Use the \`setup_project_docs\` tool to create these documents with templates:
|
|
13085
|
-
|
|
13086
|
-
\`\`\`
|
|
13087
|
-
setup_project_docs({
|
|
13088
|
-
architecture: "${defaults.architecture}", // or other available options
|
|
13089
|
-
requirements: "${defaults.requirements}", // or other available options
|
|
13090
|
-
design: "${defaults.design}" // or other available options
|
|
13091
|
-
})
|
|
13092
|
-
\`\`\`
|
|
13093
|
-
|
|
13094
|
-
${templateOptionsText}
|
|
13095
|
-
|
|
13096
|
-
## \u26A1 **Next Steps**
|
|
13097
|
-
|
|
13098
|
-
1. **Call \`setup_project_docs\`** with your preferred templates
|
|
13099
|
-
2. **Call \`start_development\`** again to begin the ${workflowName} workflow
|
|
13100
|
-
3. The workflow will reference these documents using the detected variables: ${referencedVariablesList}
|
|
13101
|
-
|
|
13102
|
-
**Note:** You can also proceed without structured docs, but the workflow instructions will reference missing files.`;
|
|
13103
|
-
}
|
|
13104
|
-
/**
|
|
13105
|
-
* Generate template options text dynamically
|
|
13106
|
-
*/
|
|
13107
|
-
generateTemplateOptionsText(availableTemplates) {
|
|
13108
|
-
const sections = [];
|
|
13109
|
-
if (availableTemplates.architecture.length > 0) {
|
|
13110
|
-
const archOptions = availableTemplates.architecture.map((template) => {
|
|
13111
|
-
const description = this.getTemplateDescription(
|
|
13112
|
-
template,
|
|
13113
|
-
"architecture"
|
|
13114
|
-
);
|
|
13115
|
-
return `- **${template}**: ${description}`;
|
|
13116
|
-
}).join("\n");
|
|
13117
|
-
sections.push(`**Architecture Templates:**
|
|
13118
|
-
${archOptions}`);
|
|
13119
|
-
}
|
|
13120
|
-
if (availableTemplates.requirements.length > 0) {
|
|
13121
|
-
const reqOptions = availableTemplates.requirements.map((template) => {
|
|
13122
|
-
const description = this.getTemplateDescription(
|
|
13123
|
-
template,
|
|
13124
|
-
"requirements"
|
|
13125
|
-
);
|
|
13126
|
-
return `- **${template}**: ${description}`;
|
|
13127
|
-
}).join("\n");
|
|
13128
|
-
sections.push(`**Requirements Templates:**
|
|
13129
|
-
${reqOptions}`);
|
|
13130
|
-
}
|
|
13131
|
-
if (availableTemplates.design.length > 0) {
|
|
13132
|
-
const designOptions = availableTemplates.design.map((template) => {
|
|
13133
|
-
const description = this.getTemplateDescription(template, "design");
|
|
13134
|
-
return `- **${template}**: ${description}`;
|
|
13135
|
-
}).join("\n");
|
|
13136
|
-
sections.push(`**Design Templates:**
|
|
13137
|
-
${designOptions}`);
|
|
13138
|
-
}
|
|
13139
|
-
return sections.length > 0 ? `## \u{1F4CB} **Template Options**
|
|
13140
|
-
|
|
13141
|
-
${sections.join("\n\n")}` : "";
|
|
13142
|
-
}
|
|
13143
|
-
/**
|
|
13144
|
-
* Get description for a template based on its name and type
|
|
13145
|
-
*/
|
|
13146
|
-
getTemplateDescription(template, type2) {
|
|
13147
|
-
switch (template) {
|
|
13148
|
-
case "arc42":
|
|
13149
|
-
return "Comprehensive software architecture template with diagrams";
|
|
13150
|
-
case "ears":
|
|
13151
|
-
return "WHEN...THEN format for clear, testable requirements";
|
|
13152
|
-
case "comprehensive":
|
|
13153
|
-
return "Full implementation guide with testing strategy";
|
|
13154
|
-
case "freestyle":
|
|
13155
|
-
return `Simple, flexible ${type2} documentation`;
|
|
13156
|
-
default:
|
|
13157
|
-
return `${template} format for ${type2} documentation`;
|
|
13158
|
-
}
|
|
12802
|
+
Then retry \`start_development\`.`;
|
|
13159
12803
|
}
|
|
13160
12804
|
/**
|
|
13161
12805
|
* Generate workflow documentation URL for predefined workflows
|
|
@@ -13510,12 +13154,12 @@ var ResetDevelopmentHandler = class extends BaseToolHandler {
|
|
|
13510
13154
|
return result;
|
|
13511
13155
|
}
|
|
13512
13156
|
};
|
|
13513
|
-
var
|
|
13157
|
+
var logger16 = createLogger("ListWorkflowsHandler");
|
|
13514
13158
|
var ListWorkflowsArgsSchema = external_exports.object({});
|
|
13515
13159
|
var ListWorkflowsHandler = class extends BaseToolHandler {
|
|
13516
13160
|
argsSchema = ListWorkflowsArgsSchema;
|
|
13517
13161
|
async executeHandler(_args, context) {
|
|
13518
|
-
|
|
13162
|
+
logger16.info("Listing available workflows", {
|
|
13519
13163
|
projectPath: context.projectPath
|
|
13520
13164
|
});
|
|
13521
13165
|
const availableWorkflows = context.workflowManager.getAvailableWorkflowsForProject(
|
|
@@ -13530,18 +13174,18 @@ var ListWorkflowsHandler = class extends BaseToolHandler {
|
|
|
13530
13174
|
const response = {
|
|
13531
13175
|
workflows
|
|
13532
13176
|
};
|
|
13533
|
-
|
|
13177
|
+
logger16.info("Successfully listed workflows", {
|
|
13534
13178
|
count: workflows.length,
|
|
13535
13179
|
workflows: workflows.map((w) => w.name)
|
|
13536
13180
|
});
|
|
13537
13181
|
return response;
|
|
13538
13182
|
}
|
|
13539
13183
|
};
|
|
13540
|
-
var
|
|
13184
|
+
var logger17 = createLogger("VersionInfo");
|
|
13541
13185
|
var BUILD_TIME_VERSION = null;
|
|
13542
13186
|
function getVersionFromPackageJson() {
|
|
13543
13187
|
try {
|
|
13544
|
-
const currentDir =
|
|
13188
|
+
const currentDir = dirname6(fileURLToPath4(import.meta.url));
|
|
13545
13189
|
const packageJsonPaths = [
|
|
13546
13190
|
join8(currentDir, "..", "package.json"),
|
|
13547
13191
|
join8(currentDir, "..", "..", "..", "package.json")
|
|
@@ -13550,7 +13194,7 @@ function getVersionFromPackageJson() {
|
|
|
13550
13194
|
try {
|
|
13551
13195
|
const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
|
|
13552
13196
|
if (packageJson.version) {
|
|
13553
|
-
|
|
13197
|
+
logger17.debug("Found version in package.json", {
|
|
13554
13198
|
path: packageJsonPath,
|
|
13555
13199
|
version: packageJson.version
|
|
13556
13200
|
});
|
|
@@ -13560,7 +13204,7 @@ function getVersionFromPackageJson() {
|
|
|
13560
13204
|
};
|
|
13561
13205
|
}
|
|
13562
13206
|
} catch (error) {
|
|
13563
|
-
|
|
13207
|
+
logger17.debug("Could not read package.json", {
|
|
13564
13208
|
path: packageJsonPath,
|
|
13565
13209
|
error: error instanceof Error ? error.message : String(error)
|
|
13566
13210
|
});
|
|
@@ -13568,7 +13212,7 @@ function getVersionFromPackageJson() {
|
|
|
13568
13212
|
}
|
|
13569
13213
|
return null;
|
|
13570
13214
|
} catch (error) {
|
|
13571
|
-
|
|
13215
|
+
logger17.debug("Error getting version from package.json", { error });
|
|
13572
13216
|
return null;
|
|
13573
13217
|
}
|
|
13574
13218
|
}
|
|
@@ -13578,7 +13222,7 @@ function getVersionFromGit() {
|
|
|
13578
13222
|
encoding: "utf-8",
|
|
13579
13223
|
stdio: "pipe"
|
|
13580
13224
|
}).trim();
|
|
13581
|
-
|
|
13225
|
+
logger17.debug("Git describe output", { gitDescribe });
|
|
13582
13226
|
const isDirty2 = gitDescribe.endsWith("-dirty");
|
|
13583
13227
|
const cleanDescribe = isDirty2 ? gitDescribe.slice(0, -6) : gitDescribe;
|
|
13584
13228
|
const parts = cleanDescribe.split("-");
|
|
@@ -13603,16 +13247,16 @@ function getVersionFromGit() {
|
|
|
13603
13247
|
source: "git"
|
|
13604
13248
|
};
|
|
13605
13249
|
} catch (error) {
|
|
13606
|
-
|
|
13250
|
+
logger17.debug("Error getting version from git", {
|
|
13607
13251
|
error: error instanceof Error ? error.message : String(error)
|
|
13608
13252
|
});
|
|
13609
13253
|
return null;
|
|
13610
13254
|
}
|
|
13611
13255
|
}
|
|
13612
13256
|
function getVersionInfo() {
|
|
13613
|
-
|
|
13257
|
+
logger17.debug("Determining version information");
|
|
13614
13258
|
if (BUILD_TIME_VERSION) {
|
|
13615
|
-
|
|
13259
|
+
logger17.info("Using build-time version information", {
|
|
13616
13260
|
version: BUILD_TIME_VERSION.version,
|
|
13617
13261
|
source: BUILD_TIME_VERSION.source
|
|
13618
13262
|
});
|
|
@@ -13622,7 +13266,7 @@ function getVersionInfo() {
|
|
|
13622
13266
|
if (gitVersion) {
|
|
13623
13267
|
const packageVersion2 = getVersionFromPackageJson();
|
|
13624
13268
|
if (packageVersion2 && gitVersion.version === "unknown") {
|
|
13625
|
-
|
|
13269
|
+
logger17.info("Using package.json version with git commit info", {
|
|
13626
13270
|
version: packageVersion2.version,
|
|
13627
13271
|
commit: gitVersion.commit || "unknown",
|
|
13628
13272
|
isDirty: String(gitVersion.isDirty || false)
|
|
@@ -13633,7 +13277,7 @@ function getVersionInfo() {
|
|
|
13633
13277
|
source: "git"
|
|
13634
13278
|
};
|
|
13635
13279
|
}
|
|
13636
|
-
|
|
13280
|
+
logger17.info("Using git version information", {
|
|
13637
13281
|
version: gitVersion.version,
|
|
13638
13282
|
source: gitVersion.source,
|
|
13639
13283
|
commit: gitVersion.commit || "none",
|
|
@@ -13643,13 +13287,13 @@ function getVersionInfo() {
|
|
|
13643
13287
|
}
|
|
13644
13288
|
const packageVersion = getVersionFromPackageJson();
|
|
13645
13289
|
if (packageVersion) {
|
|
13646
|
-
|
|
13290
|
+
logger17.info("Using package.json version information", {
|
|
13647
13291
|
version: packageVersion.version,
|
|
13648
13292
|
source: packageVersion.source
|
|
13649
13293
|
});
|
|
13650
13294
|
return packageVersion;
|
|
13651
13295
|
}
|
|
13652
|
-
|
|
13296
|
+
logger17.warn("Could not determine version information, using fallback");
|
|
13653
13297
|
return {
|
|
13654
13298
|
version: "unknown",
|
|
13655
13299
|
source: "fallback"
|
|
@@ -13666,14 +13310,14 @@ function getFormattedVersion() {
|
|
|
13666
13310
|
}
|
|
13667
13311
|
return formatted;
|
|
13668
13312
|
}
|
|
13669
|
-
var
|
|
13313
|
+
var logger18 = createLogger("GetToolInfoHandler");
|
|
13670
13314
|
var GetToolInfoArgsSchema = external_exports.object({
|
|
13671
13315
|
// No input parameters needed
|
|
13672
13316
|
});
|
|
13673
13317
|
var GetToolInfoHandler = class extends BaseToolHandler {
|
|
13674
13318
|
argsSchema = GetToolInfoArgsSchema;
|
|
13675
13319
|
async executeHandler(_args, context) {
|
|
13676
|
-
|
|
13320
|
+
logger18.info("Generating comprehensive tool information", {
|
|
13677
13321
|
projectPath: context.projectPath
|
|
13678
13322
|
});
|
|
13679
13323
|
const availableWorkflows = context.workflowManager.getAvailableWorkflowsForProject(
|
|
@@ -13763,7 +13407,7 @@ var GetToolInfoHandler = class extends BaseToolHandler {
|
|
|
13763
13407
|
plan_file_path: conversationContext.planFilePath
|
|
13764
13408
|
};
|
|
13765
13409
|
} catch (error) {
|
|
13766
|
-
|
|
13410
|
+
logger18.debug("No active conversation found for workflow state", {
|
|
13767
13411
|
error
|
|
13768
13412
|
});
|
|
13769
13413
|
}
|
|
@@ -13790,7 +13434,7 @@ var GetToolInfoHandler = class extends BaseToolHandler {
|
|
|
13790
13434
|
if (workflowState) {
|
|
13791
13435
|
response.workflow_states = workflowState;
|
|
13792
13436
|
}
|
|
13793
|
-
|
|
13437
|
+
logger18.info("Successfully generated tool information", {
|
|
13794
13438
|
toolCount: tools.length,
|
|
13795
13439
|
workflowCount: workflows.length,
|
|
13796
13440
|
hasWorkflowState: !!workflowState
|
|
@@ -13808,22 +13452,25 @@ var GetToolInfoHandler = class extends BaseToolHandler {
|
|
|
13808
13452
|
}
|
|
13809
13453
|
};
|
|
13810
13454
|
var SetupProjectDocsHandler = class extends BaseToolHandler {
|
|
13811
|
-
projectDocsManager;
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
13455
|
+
projectDocsManager = null;
|
|
13456
|
+
getProjectDocsManager() {
|
|
13457
|
+
if (!this.projectDocsManager) {
|
|
13458
|
+
this.projectDocsManager = new ProjectDocsManager(this.logger);
|
|
13459
|
+
}
|
|
13460
|
+
return this.projectDocsManager;
|
|
13815
13461
|
}
|
|
13816
13462
|
async executeHandler(args, context) {
|
|
13817
13463
|
const projectPath = stripVibePathSuffix(
|
|
13818
13464
|
args.project_path,
|
|
13819
13465
|
context.projectPath || process.cwd()
|
|
13820
13466
|
);
|
|
13467
|
+
const projectDocsManager = this.getProjectDocsManager();
|
|
13821
13468
|
this.logger.info(
|
|
13822
13469
|
"Setting up project docs with enhanced file linking support",
|
|
13823
13470
|
{ args, projectPath }
|
|
13824
13471
|
);
|
|
13825
13472
|
try {
|
|
13826
|
-
const availableTemplates = await
|
|
13473
|
+
const availableTemplates = await projectDocsManager.templateManager.getAvailableTemplates();
|
|
13827
13474
|
const processedArgs = await this.validateAndProcessArgs(
|
|
13828
13475
|
args,
|
|
13829
13476
|
availableTemplates,
|
|
@@ -13835,7 +13482,7 @@ var SetupProjectDocsHandler = class extends BaseToolHandler {
|
|
|
13835
13482
|
created: [],
|
|
13836
13483
|
linked: [],
|
|
13837
13484
|
skipped: [],
|
|
13838
|
-
paths:
|
|
13485
|
+
paths: projectDocsManager.getDocumentPaths(projectPath),
|
|
13839
13486
|
message: processedArgs.error || "Unknown error during validation"
|
|
13840
13487
|
};
|
|
13841
13488
|
}
|
|
@@ -13844,12 +13491,12 @@ var SetupProjectDocsHandler = class extends BaseToolHandler {
|
|
|
13844
13491
|
"Invalid processed args: missing templateOptions or filePaths"
|
|
13845
13492
|
);
|
|
13846
13493
|
}
|
|
13847
|
-
const result = await
|
|
13494
|
+
const result = await projectDocsManager.createOrLinkProjectDocs(
|
|
13848
13495
|
projectPath,
|
|
13849
13496
|
processedArgs.templateOptions,
|
|
13850
13497
|
processedArgs.filePaths
|
|
13851
13498
|
);
|
|
13852
|
-
const paths =
|
|
13499
|
+
const paths = projectDocsManager.getDocumentPaths(projectPath);
|
|
13853
13500
|
let message = "Project documentation setup completed.";
|
|
13854
13501
|
if (result.created.length > 0) {
|
|
13855
13502
|
message += ` Created: ${result.created.join(", ")}.`;
|
|
@@ -13884,7 +13531,7 @@ var SetupProjectDocsHandler = class extends BaseToolHandler {
|
|
|
13884
13531
|
created: [],
|
|
13885
13532
|
linked: [],
|
|
13886
13533
|
skipped: [],
|
|
13887
|
-
paths:
|
|
13534
|
+
paths: projectDocsManager.getDocumentPaths(projectPath),
|
|
13888
13535
|
message: `Failed to setup project docs: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
13889
13536
|
};
|
|
13890
13537
|
}
|
|
@@ -13957,11 +13604,11 @@ var NoIdeaHandler = class extends BaseToolHandler {
|
|
|
13957
13604
|
return { instructions };
|
|
13958
13605
|
}
|
|
13959
13606
|
};
|
|
13960
|
-
var
|
|
13607
|
+
var logger19 = createLogger("ToolRegistry");
|
|
13961
13608
|
var DefaultToolRegistry = class {
|
|
13962
13609
|
handlers = /* @__PURE__ */ new Map();
|
|
13963
13610
|
register(name, handler) {
|
|
13964
|
-
|
|
13611
|
+
logger19.debug("Registering tool handler", {
|
|
13965
13612
|
name,
|
|
13966
13613
|
handlerType: handler.constructor.name
|
|
13967
13614
|
});
|
|
@@ -13986,15 +13633,22 @@ function createToolRegistry() {
|
|
|
13986
13633
|
registry.register("get_tool_info", new GetToolInfoHandler());
|
|
13987
13634
|
registry.register("setup_project_docs", new SetupProjectDocsHandler());
|
|
13988
13635
|
registry.register("no_idea", new NoIdeaHandler());
|
|
13989
|
-
|
|
13636
|
+
logger19.info("Tool registry created with handlers", {
|
|
13990
13637
|
handlers: registry.list()
|
|
13991
13638
|
});
|
|
13992
13639
|
return registry;
|
|
13993
13640
|
}
|
|
13994
|
-
var
|
|
13641
|
+
var defaultLogger8 = createLogger("DevelopmentPlanResourceHandler");
|
|
13995
13642
|
var DevelopmentPlanResourceHandler = class {
|
|
13643
|
+
logger;
|
|
13644
|
+
constructor(logger24) {
|
|
13645
|
+
this.logger = logger24 ?? defaultLogger8;
|
|
13646
|
+
}
|
|
13996
13647
|
async handle(uri, context) {
|
|
13997
|
-
|
|
13648
|
+
if (context.loggerFactory) {
|
|
13649
|
+
this.logger = context.loggerFactory("DevelopmentPlanResourceHandler");
|
|
13650
|
+
}
|
|
13651
|
+
this.logger.debug("Processing development plan resource request", {
|
|
13998
13652
|
uri: uri.href
|
|
13999
13653
|
});
|
|
14000
13654
|
return safeExecute(async () => {
|
|
@@ -14010,10 +13664,17 @@ var DevelopmentPlanResourceHandler = class {
|
|
|
14010
13664
|
}, "Failed to retrieve development plan resource");
|
|
14011
13665
|
}
|
|
14012
13666
|
};
|
|
14013
|
-
var
|
|
13667
|
+
var defaultLogger9 = createLogger("ConversationStateResourceHandler");
|
|
14014
13668
|
var ConversationStateResourceHandler = class {
|
|
13669
|
+
logger;
|
|
13670
|
+
constructor(logger24) {
|
|
13671
|
+
this.logger = logger24 ?? defaultLogger9;
|
|
13672
|
+
}
|
|
14015
13673
|
async handle(uri, context) {
|
|
14016
|
-
|
|
13674
|
+
if (context.loggerFactory) {
|
|
13675
|
+
this.logger = context.loggerFactory("ConversationStateResourceHandler");
|
|
13676
|
+
}
|
|
13677
|
+
this.logger.debug("Processing conversation state resource request", {
|
|
14017
13678
|
uri: uri.href
|
|
14018
13679
|
});
|
|
14019
13680
|
return safeExecute(async () => {
|
|
@@ -14035,10 +13696,19 @@ var ConversationStateResourceHandler = class {
|
|
|
14035
13696
|
}, "Failed to retrieve conversation state resource");
|
|
14036
13697
|
}
|
|
14037
13698
|
};
|
|
14038
|
-
var
|
|
13699
|
+
var defaultLogger10 = createLogger("WorkflowResourceHandler");
|
|
14039
13700
|
var WorkflowResourceHandler = class {
|
|
13701
|
+
logger;
|
|
13702
|
+
constructor(logger24) {
|
|
13703
|
+
this.logger = logger24 ?? defaultLogger10;
|
|
13704
|
+
}
|
|
14040
13705
|
async handle(uri, context) {
|
|
14041
|
-
|
|
13706
|
+
if (context.loggerFactory) {
|
|
13707
|
+
this.logger = context.loggerFactory("WorkflowResourceHandler");
|
|
13708
|
+
}
|
|
13709
|
+
this.logger.debug("Processing workflow resource request", {
|
|
13710
|
+
uri: uri.href
|
|
13711
|
+
});
|
|
14042
13712
|
return safeExecute(async () => {
|
|
14043
13713
|
const workflowName = uri.hostname;
|
|
14044
13714
|
if (!workflowName) {
|
|
@@ -14046,7 +13716,10 @@ var WorkflowResourceHandler = class {
|
|
|
14046
13716
|
"Invalid workflow URI: missing workflow name. Expected: workflow://workflow-name"
|
|
14047
13717
|
);
|
|
14048
13718
|
}
|
|
14049
|
-
|
|
13719
|
+
this.logger.info("Loading workflow resource", {
|
|
13720
|
+
workflowName,
|
|
13721
|
+
uri: uri.href
|
|
13722
|
+
});
|
|
14050
13723
|
let yamlContent;
|
|
14051
13724
|
let filePath;
|
|
14052
13725
|
const workflow = context.workflowManager.getWorkflow(workflowName);
|
|
@@ -14076,7 +13749,7 @@ var WorkflowResourceHandler = class {
|
|
|
14076
13749
|
`${workflowName}.yml`
|
|
14077
13750
|
);
|
|
14078
13751
|
if (!fs5.existsSync(workflowFileYml)) {
|
|
14079
|
-
|
|
13752
|
+
this.logger.error(
|
|
14080
13753
|
"Workflow file not found",
|
|
14081
13754
|
new Error(`Workflow '${workflowName}' not found`),
|
|
14082
13755
|
{
|
|
@@ -14100,7 +13773,7 @@ var WorkflowResourceHandler = class {
|
|
|
14100
13773
|
filePath = workflowFile;
|
|
14101
13774
|
}
|
|
14102
13775
|
yamlContent = fs5.readFileSync(filePath, "utf-8");
|
|
14103
|
-
|
|
13776
|
+
this.logger.info("Successfully loaded workflow resource", {
|
|
14104
13777
|
workflowName,
|
|
14105
13778
|
filePath,
|
|
14106
13779
|
contentLength: yamlContent.length
|
|
@@ -14113,17 +13786,24 @@ var WorkflowResourceHandler = class {
|
|
|
14113
13786
|
}, `Failed to load workflow resource: ${uri.href}`);
|
|
14114
13787
|
}
|
|
14115
13788
|
};
|
|
14116
|
-
var
|
|
13789
|
+
var defaultLogger11 = createLogger("SystemPromptResourceHandler");
|
|
14117
13790
|
var SystemPromptResourceHandler = class {
|
|
14118
|
-
|
|
14119
|
-
|
|
13791
|
+
logger;
|
|
13792
|
+
constructor(logger24) {
|
|
13793
|
+
this.logger = logger24 ?? defaultLogger11;
|
|
13794
|
+
}
|
|
13795
|
+
async handle(uri, context) {
|
|
13796
|
+
if (context.loggerFactory) {
|
|
13797
|
+
this.logger = context.loggerFactory("SystemPromptResourceHandler");
|
|
13798
|
+
}
|
|
13799
|
+
this.logger.debug("Processing system prompt resource request", {
|
|
14120
13800
|
uri: uri.href
|
|
14121
13801
|
});
|
|
14122
13802
|
return safeExecute(async () => {
|
|
14123
13803
|
const loader2 = new StateMachineLoader();
|
|
14124
13804
|
const stateMachine = loader2.loadStateMachine(process.cwd());
|
|
14125
13805
|
const systemPrompt = generateSystemPrompt(stateMachine);
|
|
14126
|
-
|
|
13806
|
+
this.logger.debug("Generated system prompt for resource", {
|
|
14127
13807
|
promptLength: systemPrompt.length,
|
|
14128
13808
|
workflowName: stateMachine.name
|
|
14129
13809
|
});
|
|
@@ -14135,11 +13815,11 @@ var SystemPromptResourceHandler = class {
|
|
|
14135
13815
|
}, "Failed to retrieve system prompt resource");
|
|
14136
13816
|
}
|
|
14137
13817
|
};
|
|
14138
|
-
var
|
|
13818
|
+
var logger20 = createLogger("ResourceRegistry");
|
|
14139
13819
|
var DefaultResourceRegistry = class {
|
|
14140
13820
|
handlers = /* @__PURE__ */ new Map();
|
|
14141
13821
|
register(pattern, handler) {
|
|
14142
|
-
|
|
13822
|
+
logger20.debug("Registering resource handler", {
|
|
14143
13823
|
pattern,
|
|
14144
13824
|
handlerType: handler.constructor.name
|
|
14145
13825
|
});
|
|
@@ -14148,11 +13828,11 @@ var DefaultResourceRegistry = class {
|
|
|
14148
13828
|
resolve(uri) {
|
|
14149
13829
|
for (const [pattern, handler] of this.handlers.entries()) {
|
|
14150
13830
|
if (uri.includes(pattern)) {
|
|
14151
|
-
|
|
13831
|
+
logger20.debug("Resolved resource handler", { uri, pattern });
|
|
14152
13832
|
return handler;
|
|
14153
13833
|
}
|
|
14154
13834
|
}
|
|
14155
|
-
|
|
13835
|
+
logger20.debug("No resource handler found for URI", { uri });
|
|
14156
13836
|
return void 0;
|
|
14157
13837
|
}
|
|
14158
13838
|
};
|
|
@@ -14162,7 +13842,7 @@ function createResourceRegistry() {
|
|
|
14162
13842
|
registry.register("state://current", new ConversationStateResourceHandler());
|
|
14163
13843
|
registry.register("workflow://", new WorkflowResourceHandler());
|
|
14164
13844
|
registry.register("system-prompt://", new SystemPromptResourceHandler());
|
|
14165
|
-
|
|
13845
|
+
logger20.info("Resource registry created with handlers", {
|
|
14166
13846
|
patterns: [
|
|
14167
13847
|
"plan://current",
|
|
14168
13848
|
"state://current",
|
|
@@ -14172,13 +13852,13 @@ function createResourceRegistry() {
|
|
|
14172
13852
|
});
|
|
14173
13853
|
return registry;
|
|
14174
13854
|
}
|
|
14175
|
-
var
|
|
13855
|
+
var logger21 = createLogger("ResponseRenderer");
|
|
14176
13856
|
var DefaultResponseRenderer = class {
|
|
14177
13857
|
/**
|
|
14178
13858
|
* Render a tool handler result as an MCP tool response
|
|
14179
13859
|
*/
|
|
14180
13860
|
renderToolResponse(result) {
|
|
14181
|
-
|
|
13861
|
+
logger21.debug("Rendering tool response", {
|
|
14182
13862
|
success: result.success,
|
|
14183
13863
|
hasData: !!result.data,
|
|
14184
13864
|
hasError: !!result.error
|
|
@@ -14200,7 +13880,7 @@ var DefaultResponseRenderer = class {
|
|
|
14200
13880
|
* Render a resource handler result as an MCP resource response
|
|
14201
13881
|
*/
|
|
14202
13882
|
renderResourceResponse(result) {
|
|
14203
|
-
|
|
13883
|
+
logger21.debug("Rendering resource response", {
|
|
14204
13884
|
success: result.success,
|
|
14205
13885
|
hasData: !!result.data
|
|
14206
13886
|
});
|
|
@@ -14231,7 +13911,7 @@ var DefaultResponseRenderer = class {
|
|
|
14231
13911
|
*/
|
|
14232
13912
|
renderError(error) {
|
|
14233
13913
|
const errorMessage = error instanceof Error ? error.message : error;
|
|
14234
|
-
|
|
13914
|
+
logger21.debug("Rendering error response", { errorMessage });
|
|
14235
13915
|
return {
|
|
14236
13916
|
content: [
|
|
14237
13917
|
{
|
|
@@ -14246,7 +13926,50 @@ var DefaultResponseRenderer = class {
|
|
|
14246
13926
|
function createResponseRenderer() {
|
|
14247
13927
|
return new DefaultResponseRenderer();
|
|
14248
13928
|
}
|
|
14249
|
-
|
|
13929
|
+
function capitalizePhase2(phase) {
|
|
13930
|
+
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
13931
|
+
}
|
|
13932
|
+
function createMcpLogSink(mcpServer) {
|
|
13933
|
+
return {
|
|
13934
|
+
async log(level, logger24, message, context) {
|
|
13935
|
+
try {
|
|
13936
|
+
let enhancedMessage = message;
|
|
13937
|
+
let notificationLevel = level;
|
|
13938
|
+
if (context && (context["from"] || context["to"]) && message.includes("transition")) {
|
|
13939
|
+
const from = context["from"] ? capitalizePhase2(context["from"]) : "";
|
|
13940
|
+
const to = context["to"] ? capitalizePhase2(context["to"]) : "";
|
|
13941
|
+
if (from && to) {
|
|
13942
|
+
enhancedMessage = `Phase Transition: ${from} \u2192 ${to}`;
|
|
13943
|
+
notificationLevel = "info";
|
|
13944
|
+
}
|
|
13945
|
+
}
|
|
13946
|
+
if (message.includes("initialized successfully")) {
|
|
13947
|
+
enhancedMessage = "\u{1F680} Vibe Feature MCP Server Ready";
|
|
13948
|
+
notificationLevel = "info";
|
|
13949
|
+
}
|
|
13950
|
+
let logData = enhancedMessage;
|
|
13951
|
+
if (context) {
|
|
13952
|
+
try {
|
|
13953
|
+
const contextStr = JSON.stringify(context, null, 0);
|
|
13954
|
+
logData = `${enhancedMessage} ${contextStr}`;
|
|
13955
|
+
} catch (_error) {
|
|
13956
|
+
logData = `${enhancedMessage} [context serialization failed]`;
|
|
13957
|
+
}
|
|
13958
|
+
}
|
|
13959
|
+
await mcpServer.server.notification({
|
|
13960
|
+
method: "notifications/message",
|
|
13961
|
+
params: {
|
|
13962
|
+
level: notificationLevel,
|
|
13963
|
+
logger: logger24,
|
|
13964
|
+
data: logData
|
|
13965
|
+
}
|
|
13966
|
+
});
|
|
13967
|
+
} catch (_error) {
|
|
13968
|
+
}
|
|
13969
|
+
}
|
|
13970
|
+
};
|
|
13971
|
+
}
|
|
13972
|
+
var logger22 = createLogger("ResponsibleVibeMCPServer");
|
|
14250
13973
|
async function createResponsibleVibeMCPServer(config = {}) {
|
|
14251
13974
|
const components = await initializeServerComponents(config);
|
|
14252
13975
|
return new ResponsibleVibeMCPServer(config, components);
|
|
@@ -14255,7 +13978,7 @@ var ResponsibleVibeMCPServer = class {
|
|
|
14255
13978
|
constructor(config, serverComponents) {
|
|
14256
13979
|
this.config = config;
|
|
14257
13980
|
this.serverComponents = serverComponents;
|
|
14258
|
-
|
|
13981
|
+
logger22.debug("ResponsibleVibeMCPServer created", {
|
|
14259
13982
|
config: JSON.stringify(this.config)
|
|
14260
13983
|
});
|
|
14261
13984
|
}
|
|
@@ -14264,7 +13987,7 @@ var ResponsibleVibeMCPServer = class {
|
|
|
14264
13987
|
* Initialize the server and all its components
|
|
14265
13988
|
*/
|
|
14266
13989
|
async initialize() {
|
|
14267
|
-
|
|
13990
|
+
logger22.debug("Initializing ResponsibleVibeMCPServer");
|
|
14268
13991
|
try {
|
|
14269
13992
|
this.components = this.serverComponents;
|
|
14270
13993
|
const toolRegistry = createToolRegistry();
|
|
@@ -14273,7 +13996,7 @@ var ResponsibleVibeMCPServer = class {
|
|
|
14273
13996
|
this.components.toolRegistry = toolRegistry;
|
|
14274
13997
|
this.components.resourceRegistry = resourceRegistry;
|
|
14275
13998
|
this.components.responseRenderer = responseRenderer;
|
|
14276
|
-
|
|
13999
|
+
registerLogSink(createMcpLogSink(this.components.mcpServer));
|
|
14277
14000
|
await registerMcpTools(
|
|
14278
14001
|
this.components.mcpServer,
|
|
14279
14002
|
toolRegistry,
|
|
@@ -14287,7 +14010,7 @@ var ResponsibleVibeMCPServer = class {
|
|
|
14287
14010
|
this.components.context
|
|
14288
14011
|
);
|
|
14289
14012
|
} catch (error) {
|
|
14290
|
-
|
|
14013
|
+
logger22.error(
|
|
14291
14014
|
"Failed to initialize ResponsibleVibeMCPServer",
|
|
14292
14015
|
error
|
|
14293
14016
|
);
|
|
@@ -14420,14 +14143,14 @@ var ResponsibleVibeMCPServer = class {
|
|
|
14420
14143
|
* Cleanup server resources
|
|
14421
14144
|
*/
|
|
14422
14145
|
async cleanup() {
|
|
14423
|
-
|
|
14146
|
+
logger22.debug("Cleaning up server resources");
|
|
14424
14147
|
if (this.components?.database) {
|
|
14425
14148
|
await this.components.database.close();
|
|
14426
14149
|
}
|
|
14427
|
-
|
|
14150
|
+
logger22.info("Server cleanup completed");
|
|
14428
14151
|
}
|
|
14429
14152
|
};
|
|
14430
|
-
var
|
|
14153
|
+
var logger23 = createLogger("Main");
|
|
14431
14154
|
function parseCliArgs() {
|
|
14432
14155
|
return { shouldStartServer: true };
|
|
14433
14156
|
}
|
|
@@ -14445,30 +14168,46 @@ async function main() {
|
|
|
14445
14168
|
const transport = new StdioServerTransport();
|
|
14446
14169
|
await server.getMcpServer().connect(transport);
|
|
14447
14170
|
process.on("SIGINT", async () => {
|
|
14448
|
-
|
|
14171
|
+
logger23.info("Shutting down Vibe Feature MCP Server...");
|
|
14449
14172
|
await server.cleanup();
|
|
14450
14173
|
process.exit(0);
|
|
14451
14174
|
});
|
|
14452
14175
|
process.on("SIGTERM", async () => {
|
|
14453
|
-
|
|
14176
|
+
logger23.info("Shutting down Vibe Feature MCP Server...");
|
|
14454
14177
|
await server.cleanup();
|
|
14455
14178
|
process.exit(0);
|
|
14456
14179
|
});
|
|
14457
14180
|
} catch (error) {
|
|
14458
|
-
|
|
14181
|
+
logger23.error("Failed to start server", error);
|
|
14459
14182
|
process.exit(1);
|
|
14460
14183
|
}
|
|
14461
14184
|
}
|
|
14462
14185
|
var isMainModule = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("ade-workflows-server") || process.argv[1]?.endsWith("index.js");
|
|
14463
14186
|
if (isMainModule) {
|
|
14464
14187
|
await main().catch((error) => {
|
|
14465
|
-
|
|
14188
|
+
logger23.error("Unhandled error in main", error);
|
|
14466
14189
|
process.exit(1);
|
|
14467
14190
|
});
|
|
14468
14191
|
}
|
|
14469
14192
|
export {
|
|
14193
|
+
BaseToolHandler,
|
|
14194
|
+
BeadsPlugin,
|
|
14195
|
+
ConductReviewHandler,
|
|
14196
|
+
ConversationRequiredToolHandler,
|
|
14197
|
+
DefaultToolRegistry,
|
|
14198
|
+
GetToolInfoHandler,
|
|
14199
|
+
ListWorkflowsHandler,
|
|
14200
|
+
NoIdeaHandler,
|
|
14201
|
+
PluginRegistry,
|
|
14202
|
+
ProceedToPhaseHandler,
|
|
14203
|
+
ResetDevelopmentHandler,
|
|
14470
14204
|
ResponsibleVibeMCPServer,
|
|
14205
|
+
ResumeWorkflowHandler,
|
|
14206
|
+
SetupProjectDocsHandler,
|
|
14207
|
+
StartDevelopmentHandler,
|
|
14208
|
+
WhatsNextHandler,
|
|
14471
14209
|
createResponsibleVibeMCPServer,
|
|
14210
|
+
createToolRegistry,
|
|
14472
14211
|
main as startMcpServer
|
|
14473
14212
|
};
|
|
14474
14213
|
/*! Bundled license information:
|