@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
|
@@ -2864,25 +2864,27 @@ var LogLevel;
|
|
|
2864
2864
|
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
2865
2865
|
LogLevel2[LogLevel2["SILENT"] = 4] = "SILENT";
|
|
2866
2866
|
})(LogLevel || (LogLevel = {}));
|
|
2867
|
-
var
|
|
2867
|
+
var logSinkInstance = null;
|
|
2868
2868
|
var currentLoggingLevel = null;
|
|
2869
2869
|
function isTestMode() {
|
|
2870
|
-
if (process.env
|
|
2870
|
+
if (process.env["NODE_ENV"] === "test" || process.env["VITEST"] === "true") {
|
|
2871
2871
|
return true;
|
|
2872
2872
|
}
|
|
2873
|
-
|
|
2874
|
-
if (cwd.includes("/tmp/") || cwd.includes("temp") || cwd.includes("test-")) {
|
|
2875
|
-
return true;
|
|
2876
|
-
}
|
|
2877
|
-
if (process.env.LOG_LEVEL === "ERROR") {
|
|
2873
|
+
if (process.env["LOG_LEVEL"] === "ERROR") {
|
|
2878
2874
|
return true;
|
|
2879
2875
|
}
|
|
2880
2876
|
return false;
|
|
2881
2877
|
}
|
|
2882
|
-
function
|
|
2883
|
-
|
|
2878
|
+
function registerLogSink(sink) {
|
|
2879
|
+
logSinkInstance = sink;
|
|
2880
|
+
}
|
|
2881
|
+
function clearLogSink() {
|
|
2882
|
+
logSinkInstance = null;
|
|
2883
|
+
}
|
|
2884
|
+
function setLoggingLevel(level) {
|
|
2885
|
+
currentLoggingLevel = level;
|
|
2884
2886
|
}
|
|
2885
|
-
function
|
|
2887
|
+
function setLoggingLevelFromString(level) {
|
|
2886
2888
|
const levelMap = {
|
|
2887
2889
|
debug: LogLevel.DEBUG,
|
|
2888
2890
|
info: LogLevel.INFO,
|
|
@@ -2922,7 +2924,7 @@ var Logger = class _Logger {
|
|
|
2922
2924
|
return LogLevel.INFO;
|
|
2923
2925
|
}
|
|
2924
2926
|
getLogLevelFromEnv() {
|
|
2925
|
-
const envLevel = process.env
|
|
2927
|
+
const envLevel = process.env["LOG_LEVEL"]?.toUpperCase();
|
|
2926
2928
|
switch (envLevel) {
|
|
2927
2929
|
case "DEBUG":
|
|
2928
2930
|
return LogLevel.DEBUG;
|
|
@@ -2947,31 +2949,15 @@ var Logger = class _Logger {
|
|
|
2947
2949
|
return `[${timestamp2}] ${level.toUpperCase()} [${this.component}] ${message}${contextStr}`;
|
|
2948
2950
|
}
|
|
2949
2951
|
/**
|
|
2950
|
-
* Send log message to
|
|
2952
|
+
* Send log message to registered sink if available
|
|
2951
2953
|
*/
|
|
2952
|
-
async
|
|
2953
|
-
if (
|
|
2954
|
+
async sendToSink(level, message, context) {
|
|
2955
|
+
if (logSinkInstance) {
|
|
2954
2956
|
try {
|
|
2955
|
-
|
|
2956
|
-
if (context) {
|
|
2957
|
-
try {
|
|
2958
|
-
const contextStr = JSON.stringify(context, null, 0);
|
|
2959
|
-
logData = `${message} ${contextStr}`;
|
|
2960
|
-
} catch (_error) {
|
|
2961
|
-
logData = `${message} [context serialization failed]`;
|
|
2962
|
-
}
|
|
2963
|
-
}
|
|
2964
|
-
await mcpServerInstance.server.notification({
|
|
2965
|
-
method: "notifications/message",
|
|
2966
|
-
params: {
|
|
2967
|
-
level,
|
|
2968
|
-
logger: this.component,
|
|
2969
|
-
data: logData
|
|
2970
|
-
}
|
|
2971
|
-
});
|
|
2957
|
+
await logSinkInstance.log(level, this.component, message, context);
|
|
2972
2958
|
} catch (error) {
|
|
2973
2959
|
if (!isTestMode()) {
|
|
2974
|
-
process.stderr.write(`[
|
|
2960
|
+
process.stderr.write(`[LOG-SINK-ERROR] Failed to send log to sink: ${error}
|
|
2975
2961
|
`);
|
|
2976
2962
|
}
|
|
2977
2963
|
}
|
|
@@ -2979,85 +2965,42 @@ var Logger = class _Logger {
|
|
|
2979
2965
|
}
|
|
2980
2966
|
debug(message, context) {
|
|
2981
2967
|
if (this.shouldLog(LogLevel.DEBUG)) {
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2968
|
+
if (!logSinkInstance) {
|
|
2969
|
+
const formattedMessage = this.formatMessage("debug", message, context);
|
|
2970
|
+
process.stderr.write(formattedMessage + "\n");
|
|
2971
|
+
}
|
|
2972
|
+
this.sendToSink("debug", message, context).catch(() => {
|
|
2985
2973
|
});
|
|
2986
2974
|
}
|
|
2987
2975
|
}
|
|
2988
2976
|
info(message, context) {
|
|
2989
2977
|
if (this.shouldLog(LogLevel.INFO)) {
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
});
|
|
2994
|
-
}
|
|
2995
|
-
}
|
|
2996
|
-
/**
|
|
2997
|
-
* Send enhanced MCP notifications with better formatting for important events
|
|
2998
|
-
*/
|
|
2999
|
-
async sendEnhancedMcpNotification(level, message, context) {
|
|
3000
|
-
if (mcpServerInstance) {
|
|
3001
|
-
try {
|
|
3002
|
-
let enhancedMessage = message;
|
|
3003
|
-
let notificationLevel = level;
|
|
3004
|
-
if (context && (context.from || context.to) && message.includes("transition")) {
|
|
3005
|
-
const from = context.from ? this.capitalizePhase(context.from) : "";
|
|
3006
|
-
const to = context.to ? this.capitalizePhase(context.to) : "";
|
|
3007
|
-
if (from && to) {
|
|
3008
|
-
enhancedMessage = `Phase Transition: ${from} \u2192 ${to}`;
|
|
3009
|
-
notificationLevel = "info";
|
|
3010
|
-
}
|
|
3011
|
-
}
|
|
3012
|
-
if (message.includes("initialized successfully")) {
|
|
3013
|
-
enhancedMessage = "\u{1F680} Vibe Feature MCP Server Ready";
|
|
3014
|
-
notificationLevel = "info";
|
|
3015
|
-
}
|
|
3016
|
-
let logData = enhancedMessage;
|
|
3017
|
-
if (context) {
|
|
3018
|
-
try {
|
|
3019
|
-
const contextStr = JSON.stringify(context, null, 0);
|
|
3020
|
-
logData = `${enhancedMessage} ${contextStr}`;
|
|
3021
|
-
} catch (_error) {
|
|
3022
|
-
logData = `${enhancedMessage} [context serialization failed]`;
|
|
3023
|
-
}
|
|
3024
|
-
}
|
|
3025
|
-
await mcpServerInstance.server.notification({
|
|
3026
|
-
method: "notifications/message",
|
|
3027
|
-
params: {
|
|
3028
|
-
level: notificationLevel,
|
|
3029
|
-
logger: this.component,
|
|
3030
|
-
data: logData
|
|
3031
|
-
}
|
|
3032
|
-
});
|
|
3033
|
-
} catch (error) {
|
|
3034
|
-
if (!isTestMode()) {
|
|
3035
|
-
process.stderr.write(`[MCP-LOG-ERROR] Failed to send log notification: ${error}
|
|
3036
|
-
`);
|
|
3037
|
-
}
|
|
2978
|
+
if (!logSinkInstance) {
|
|
2979
|
+
const formattedMessage = this.formatMessage("info", message, context);
|
|
2980
|
+
process.stderr.write(formattedMessage + "\n");
|
|
3038
2981
|
}
|
|
2982
|
+
this.sendToSink("info", message, context).catch(() => {
|
|
2983
|
+
});
|
|
3039
2984
|
}
|
|
3040
2985
|
}
|
|
3041
|
-
/**
|
|
3042
|
-
* Capitalize phase name for display
|
|
3043
|
-
*/
|
|
3044
|
-
capitalizePhase(phase) {
|
|
3045
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3046
|
-
}
|
|
3047
2986
|
warn(message, context) {
|
|
3048
2987
|
if (this.shouldLog(LogLevel.WARN)) {
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
2988
|
+
if (!logSinkInstance) {
|
|
2989
|
+
const formattedMessage = this.formatMessage("warn", message, context);
|
|
2990
|
+
process.stderr.write(formattedMessage + "\n");
|
|
2991
|
+
}
|
|
2992
|
+
this.sendToSink("warning", message, context).catch(() => {
|
|
3052
2993
|
});
|
|
3053
2994
|
}
|
|
3054
2995
|
}
|
|
3055
2996
|
error(message, error, context) {
|
|
3056
2997
|
if (this.shouldLog(LogLevel.ERROR)) {
|
|
3057
2998
|
const errorContext = error ? { ...context, error: error.message, stack: error.stack } : context;
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
2999
|
+
if (!logSinkInstance) {
|
|
3000
|
+
const formattedMessage = this.formatMessage("error", message, errorContext);
|
|
3001
|
+
process.stderr.write(formattedMessage + "\n");
|
|
3002
|
+
}
|
|
3003
|
+
this.sendToSink("error", message, errorContext).catch(() => {
|
|
3061
3004
|
});
|
|
3062
3005
|
}
|
|
3063
3006
|
}
|
|
@@ -3068,7 +3011,7 @@ var Logger = class _Logger {
|
|
|
3068
3011
|
function createLogger(component, logLevel) {
|
|
3069
3012
|
return new Logger(component, logLevel);
|
|
3070
3013
|
}
|
|
3071
|
-
var logger = createLogger("
|
|
3014
|
+
var logger = createLogger("workflows-core");
|
|
3072
3015
|
|
|
3073
3016
|
// ../core/dist/state-machine-loader.js
|
|
3074
3017
|
var logger2 = createLogger("StateMachineLoader");
|
|
@@ -3294,6 +3237,35 @@ ${continueTransition.additional_instructions}`;
|
|
|
3294
3237
|
}
|
|
3295
3238
|
return stateDefinition.default_instructions;
|
|
3296
3239
|
}
|
|
3240
|
+
/**
|
|
3241
|
+
* Get allowed file patterns for a specific phase.
|
|
3242
|
+
* Returns undefined if no restrictions are defined (all files allowed).
|
|
3243
|
+
*
|
|
3244
|
+
* @param phase - The phase/state name to get patterns for
|
|
3245
|
+
* @returns Array of glob patterns or undefined if all files are allowed
|
|
3246
|
+
*/
|
|
3247
|
+
getAllowedFilePatterns(phase) {
|
|
3248
|
+
if (!this.stateMachine) {
|
|
3249
|
+
throw new Error("State machine not loaded");
|
|
3250
|
+
}
|
|
3251
|
+
const stateDefinition = this.stateMachine.states[phase];
|
|
3252
|
+
if (!stateDefinition) {
|
|
3253
|
+
logger2.error("Unknown phase", new Error(`Unknown phase: ${phase}`));
|
|
3254
|
+
throw new Error(`Unknown phase: ${phase}`);
|
|
3255
|
+
}
|
|
3256
|
+
return stateDefinition.allowed_file_patterns;
|
|
3257
|
+
}
|
|
3258
|
+
/**
|
|
3259
|
+
* Whether the given phase restricts which files may be edited.
|
|
3260
|
+
* Returns false when no allowed_file_patterns are defined (all files allowed).
|
|
3261
|
+
* Callers should use getAllowedFilePatterns + a glob library for actual path matching.
|
|
3262
|
+
*
|
|
3263
|
+
* @param phase - The phase/state name
|
|
3264
|
+
*/
|
|
3265
|
+
hasFileRestrictions(phase) {
|
|
3266
|
+
const patterns = this.getAllowedFilePatterns(phase);
|
|
3267
|
+
return patterns !== void 0 && patterns.length > 0;
|
|
3268
|
+
}
|
|
3297
3269
|
};
|
|
3298
3270
|
|
|
3299
3271
|
// ../core/dist/workflow-manager.js
|
|
@@ -3375,13 +3347,21 @@ var WorkflowManager = class _WorkflowManager {
|
|
|
3375
3347
|
}
|
|
3376
3348
|
/**
|
|
3377
3349
|
* Parse enabled domains from environment variable
|
|
3350
|
+
* Supports both WORKFLOW_DOMAINS and VIBE_WORKFLOW_DOMAINS (legacy)
|
|
3351
|
+
* WORKFLOW_DOMAINS takes precedence if both are set (modern, non-prefixed version preferred)
|
|
3378
3352
|
*/
|
|
3379
3353
|
parseEnabledDomains() {
|
|
3380
|
-
const domainsEnv = process.env["VIBE_WORKFLOW_DOMAINS"];
|
|
3354
|
+
const domainsEnv = process.env["WORKFLOW_DOMAINS"] || process.env["VIBE_WORKFLOW_DOMAINS"];
|
|
3381
3355
|
if (!domainsEnv) {
|
|
3356
|
+
logger4.debug("No domain configuration found, using default: code");
|
|
3382
3357
|
return /* @__PURE__ */ new Set(["code"]);
|
|
3383
3358
|
}
|
|
3384
|
-
|
|
3359
|
+
const domains = new Set(domainsEnv.split(",").map((d) => d.trim()).filter((d) => d));
|
|
3360
|
+
logger4.debug("Parsed enabled domains", {
|
|
3361
|
+
source: process.env["WORKFLOW_DOMAINS"] ? "WORKFLOW_DOMAINS" : "VIBE_WORKFLOW_DOMAINS",
|
|
3362
|
+
domains: Array.from(domains)
|
|
3363
|
+
});
|
|
3364
|
+
return domains;
|
|
3385
3365
|
}
|
|
3386
3366
|
/**
|
|
3387
3367
|
* Load project-specific workflows from .vibe/workflows/
|
|
@@ -3754,16 +3734,21 @@ var WorkflowManager = class _WorkflowManager {
|
|
|
3754
3734
|
}
|
|
3755
3735
|
};
|
|
3756
3736
|
|
|
3737
|
+
// ../core/dist/string-utils.js
|
|
3738
|
+
function capitalizePhase(phase) {
|
|
3739
|
+
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3757
3742
|
// ../core/dist/transition-engine.js
|
|
3758
|
-
var
|
|
3743
|
+
var defaultLogger = createLogger("TransitionEngine");
|
|
3759
3744
|
var TransitionEngine = class {
|
|
3760
|
-
stateMachineLoader;
|
|
3761
3745
|
workflowManager;
|
|
3746
|
+
logger;
|
|
3762
3747
|
conversationManager;
|
|
3763
|
-
constructor(projectPath) {
|
|
3764
|
-
this.stateMachineLoader = new StateMachineLoader();
|
|
3748
|
+
constructor(projectPath, logger14 = defaultLogger) {
|
|
3765
3749
|
this.workflowManager = new WorkflowManager();
|
|
3766
|
-
|
|
3750
|
+
this.logger = logger14;
|
|
3751
|
+
this.logger.info("TransitionEngine initialized", { projectPath });
|
|
3767
3752
|
}
|
|
3768
3753
|
/**
|
|
3769
3754
|
* Set the conversation manager (dependency injection)
|
|
@@ -3782,11 +3767,11 @@ var TransitionEngine = class {
|
|
|
3782
3767
|
*/
|
|
3783
3768
|
async isFirstCallFromInitialState(context) {
|
|
3784
3769
|
if (!this.conversationManager) {
|
|
3785
|
-
|
|
3770
|
+
this.logger.warn("ConversationManager not set, assuming first call");
|
|
3786
3771
|
return true;
|
|
3787
3772
|
}
|
|
3788
3773
|
const hasInteractions = await this.conversationManager.hasInteractions(context.conversationId);
|
|
3789
|
-
|
|
3774
|
+
this.logger.debug("Checking first call from initial state", {
|
|
3790
3775
|
hasInteractions,
|
|
3791
3776
|
conversationId: context.conversationId,
|
|
3792
3777
|
currentPhase: context.currentPhase
|
|
@@ -3796,51 +3781,18 @@ var TransitionEngine = class {
|
|
|
3796
3781
|
/**
|
|
3797
3782
|
* Generate instructions for defining phase entrance criteria
|
|
3798
3783
|
*/
|
|
3799
|
-
|
|
3800
|
-
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
3801
|
-
const workflowName = conversationState?.workflowName;
|
|
3802
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
3784
|
+
generateCriteriaDefinitionInstructions(stateMachine) {
|
|
3803
3785
|
const phases = Object.keys(stateMachine.states);
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
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.
|
|
3807
|
-
|
|
3808
|
-
Please update the plan file with a "Phase Entrance Criteria" section that defines specific, measurable criteria for entering each phase:
|
|
3809
|
-
|
|
3810
|
-
## Phase Entrance Criteria
|
|
3811
|
-
|
|
3812
|
-
`;
|
|
3813
|
-
for (const phase of phases) {
|
|
3814
|
-
if (phase === stateMachine.initial_state)
|
|
3815
|
-
continue;
|
|
3816
|
-
const phaseDefinition = stateMachine.states[phase];
|
|
3817
|
-
const capitalizedPhase = this.capitalizePhase(phase);
|
|
3818
|
-
instructions += `### ${capitalizedPhase} Phase
|
|
3819
|
-
*${phaseDefinition.description}*
|
|
3820
|
-
|
|
3821
|
-
**Enter when:**
|
|
3822
|
-
- [ ] [Define specific criteria for entering ${phase} phase]
|
|
3823
|
-
- [ ] [Add measurable conditions that must be met]
|
|
3824
|
-
- [ ] [Include any deliverables or milestones required]
|
|
3825
|
-
|
|
3826
|
-
`;
|
|
3827
|
-
}
|
|
3828
|
-
instructions += `
|
|
3829
|
-
Once you've defined these criteria, we can begin development. Throughout the process, consult these criteria when considering phase transitions.
|
|
3830
|
-
|
|
3831
|
-
**Remember**: These criteria should be specific and measurable so we can clearly determine when each phase is ready to begin.`;
|
|
3832
|
-
return instructions;
|
|
3786
|
+
const phaseList = phases.filter((phase) => phase !== stateMachine.initial_state).map((phase) => capitalizePhase(phase)).join(", ");
|
|
3787
|
+
return `Define entrance criteria for each phase (${phaseList}) in the plan file. Criteria should be specific and measurable.`;
|
|
3833
3788
|
}
|
|
3834
3789
|
/**
|
|
3835
3790
|
* Get phase-specific instructions for continuing work in current phase
|
|
3836
3791
|
*/
|
|
3837
|
-
|
|
3838
|
-
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
3839
|
-
const workflowName = conversationState?.workflowName;
|
|
3840
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
3792
|
+
getContinuePhaseInstructions(phase, stateMachine) {
|
|
3841
3793
|
const stateDefinition = stateMachine.states[phase];
|
|
3842
3794
|
if (!stateDefinition) {
|
|
3843
|
-
|
|
3795
|
+
this.logger.error("Unknown phase", new Error(`Unknown phase: ${phase}`));
|
|
3844
3796
|
throw new Error(`Unknown phase: ${phase}`);
|
|
3845
3797
|
}
|
|
3846
3798
|
const continueTransition = stateDefinition.transitions.find((t) => t.to === phase);
|
|
@@ -3863,19 +3815,17 @@ ${continueTransition.additional_instructions}`;
|
|
|
3863
3815
|
/**
|
|
3864
3816
|
* Get the first development phase from the state machine
|
|
3865
3817
|
*/
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
const workflowName = conversationState?.workflowName;
|
|
3869
|
-
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, workflowName);
|
|
3870
|
-
const initialState = stateMachine.initial_state;
|
|
3871
|
-
return initialState;
|
|
3818
|
+
getFirstDevelopmentPhase(stateMachine) {
|
|
3819
|
+
return stateMachine.initial_state;
|
|
3872
3820
|
}
|
|
3873
3821
|
/**
|
|
3874
3822
|
* Analyze context and determine appropriate phase transition
|
|
3875
3823
|
*/
|
|
3876
3824
|
async analyzePhaseTransition(context) {
|
|
3877
3825
|
const { currentPhase, projectPath, conversationId, userInput, context: additionalContext, conversationSummary } = context;
|
|
3878
|
-
|
|
3826
|
+
const conversationState = await this.conversationManager?.getConversationState(conversationId);
|
|
3827
|
+
const stateMachine = this.workflowManager.loadWorkflowForProject(projectPath, conversationState?.workflowName);
|
|
3828
|
+
this.logger.debug("Analyzing phase transition", {
|
|
3879
3829
|
currentPhase,
|
|
3880
3830
|
projectPath,
|
|
3881
3831
|
hasUserInput: !!userInput,
|
|
@@ -3884,14 +3834,14 @@ ${continueTransition.additional_instructions}`;
|
|
|
3884
3834
|
userInput: userInput ? userInput.substring(0, 50) + (userInput.length > 50 ? "..." : "") : void 0
|
|
3885
3835
|
});
|
|
3886
3836
|
if (await this.isFirstCallFromInitialState(context)) {
|
|
3887
|
-
const firstDevelopmentPhase =
|
|
3888
|
-
|
|
3837
|
+
const firstDevelopmentPhase = this.getFirstDevelopmentPhase(stateMachine);
|
|
3838
|
+
this.logger.info("First call from initial state - transitioning to first development phase with criteria", {
|
|
3889
3839
|
currentPhase,
|
|
3890
3840
|
firstDevelopmentPhase,
|
|
3891
3841
|
projectPath
|
|
3892
3842
|
});
|
|
3893
|
-
const criteriaInstructions =
|
|
3894
|
-
const phaseInstructions =
|
|
3843
|
+
const criteriaInstructions = this.generateCriteriaDefinitionInstructions(stateMachine);
|
|
3844
|
+
const phaseInstructions = this.getContinuePhaseInstructions(firstDevelopmentPhase, stateMachine);
|
|
3895
3845
|
return {
|
|
3896
3846
|
newPhase: firstDevelopmentPhase,
|
|
3897
3847
|
// Transition to first development phase
|
|
@@ -3900,8 +3850,8 @@ ${continueTransition.additional_instructions}`;
|
|
|
3900
3850
|
isModeled: true
|
|
3901
3851
|
};
|
|
3902
3852
|
}
|
|
3903
|
-
const continueInstructions =
|
|
3904
|
-
|
|
3853
|
+
const continueInstructions = this.getContinuePhaseInstructions(currentPhase, stateMachine);
|
|
3854
|
+
this.logger.debug("Continuing in current phase - LLM will evaluate transition criteria", {
|
|
3905
3855
|
currentPhase,
|
|
3906
3856
|
projectPath
|
|
3907
3857
|
});
|
|
@@ -3917,7 +3867,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
3917
3867
|
*/
|
|
3918
3868
|
handleExplicitTransition(currentPhase, targetPhase, projectPath, reason, workflowName) {
|
|
3919
3869
|
const stateMachine = this.getStateMachine(projectPath, workflowName);
|
|
3920
|
-
|
|
3870
|
+
this.logger.debug("Handling explicit phase transition", {
|
|
3921
3871
|
currentPhase,
|
|
3922
3872
|
targetPhase,
|
|
3923
3873
|
projectPath,
|
|
@@ -3928,7 +3878,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
3928
3878
|
if (!stateMachine.states[normalizedTargetPhase]) {
|
|
3929
3879
|
const validPhases = Object.keys(stateMachine.states);
|
|
3930
3880
|
const errorMsg = `Invalid target phase: "${targetPhase}". Valid phases are: ${validPhases.join(", ")}`;
|
|
3931
|
-
|
|
3881
|
+
this.logger.error("Invalid target phase", new Error(errorMsg));
|
|
3932
3882
|
throw new Error(errorMsg);
|
|
3933
3883
|
}
|
|
3934
3884
|
const targetState = stateMachine.states[normalizedTargetPhase];
|
|
@@ -3939,7 +3889,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
3939
3889
|
isModeled: false
|
|
3940
3890
|
// Direct phase transitions are not modeled
|
|
3941
3891
|
};
|
|
3942
|
-
|
|
3892
|
+
this.logger.info("Explicit phase transition processed", {
|
|
3943
3893
|
fromPhase: currentPhase,
|
|
3944
3894
|
toPhase: normalizedTargetPhase,
|
|
3945
3895
|
reason: transitionInfo.transitionReason,
|
|
@@ -3952,12 +3902,6 @@ ${continueTransition.additional_instructions}`;
|
|
|
3952
3902
|
isModeled: transitionInfo.isModeled
|
|
3953
3903
|
};
|
|
3954
3904
|
}
|
|
3955
|
-
/**
|
|
3956
|
-
* Capitalize phase name for display
|
|
3957
|
-
*/
|
|
3958
|
-
capitalizePhase(phase) {
|
|
3959
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3960
|
-
}
|
|
3961
3905
|
/**
|
|
3962
3906
|
* Filter transitions based on agent role (for crowd workflows)
|
|
3963
3907
|
* Returns transitions applicable to the current agent
|
|
@@ -3973,7 +3917,7 @@ ${continueTransition.additional_instructions}`;
|
|
|
3973
3917
|
// ../core/dist/file-storage.js
|
|
3974
3918
|
import { promises as fs4 } from "fs";
|
|
3975
3919
|
import { join, dirname } from "path";
|
|
3976
|
-
var
|
|
3920
|
+
var logger5 = createLogger("FileStorage");
|
|
3977
3921
|
var FileStorage = class {
|
|
3978
3922
|
conversationsDir;
|
|
3979
3923
|
basePath;
|
|
@@ -3991,11 +3935,11 @@ var FileStorage = class {
|
|
|
3991
3935
|
async initialize() {
|
|
3992
3936
|
try {
|
|
3993
3937
|
await fs4.mkdir(this.conversationsDir, { recursive: true });
|
|
3994
|
-
|
|
3938
|
+
logger5.debug("FileStorage initialized", {
|
|
3995
3939
|
conversationsDir: this.conversationsDir
|
|
3996
3940
|
});
|
|
3997
3941
|
} catch (error) {
|
|
3998
|
-
|
|
3942
|
+
logger5.error("Failed to initialize FileStorage", error);
|
|
3999
3943
|
throw error;
|
|
4000
3944
|
}
|
|
4001
3945
|
}
|
|
@@ -4045,12 +3989,12 @@ var FileStorage = class {
|
|
|
4045
3989
|
await fs4.mkdir(conversationDir, { recursive: true });
|
|
4046
3990
|
const stateJson = JSON.stringify(state, null, 2);
|
|
4047
3991
|
await this.writeAtomic(stateFilePath, stateJson);
|
|
4048
|
-
|
|
3992
|
+
logger5.debug("Conversation state saved", {
|
|
4049
3993
|
conversationId: state.conversationId,
|
|
4050
3994
|
currentPhase: state.currentPhase
|
|
4051
3995
|
});
|
|
4052
3996
|
} catch (error) {
|
|
4053
|
-
|
|
3997
|
+
logger5.error("Failed to save conversation state", error, {
|
|
4054
3998
|
conversationId: state.conversationId
|
|
4055
3999
|
});
|
|
4056
4000
|
throw error;
|
|
@@ -4070,7 +4014,7 @@ var FileStorage = class {
|
|
|
4070
4014
|
if (error.code === "ENOENT") {
|
|
4071
4015
|
return null;
|
|
4072
4016
|
}
|
|
4073
|
-
|
|
4017
|
+
logger5.warn("Failed to read conversation state, returning null", {
|
|
4074
4018
|
conversationId,
|
|
4075
4019
|
error: error.message
|
|
4076
4020
|
});
|
|
@@ -4102,7 +4046,7 @@ var FileStorage = class {
|
|
|
4102
4046
|
if (error.code === "ENOENT") {
|
|
4103
4047
|
return [];
|
|
4104
4048
|
}
|
|
4105
|
-
|
|
4049
|
+
logger5.error("Failed to get all conversation states", error);
|
|
4106
4050
|
throw error;
|
|
4107
4051
|
}
|
|
4108
4052
|
}
|
|
@@ -4114,13 +4058,13 @@ var FileStorage = class {
|
|
|
4114
4058
|
const conversationDir = this.getConversationDir(conversationId);
|
|
4115
4059
|
try {
|
|
4116
4060
|
await fs4.rm(conversationDir, { recursive: true, force: true });
|
|
4117
|
-
|
|
4061
|
+
logger5.debug("Conversation state deleted", { conversationId });
|
|
4118
4062
|
return true;
|
|
4119
4063
|
} catch (error) {
|
|
4120
4064
|
if (error.code === "ENOENT") {
|
|
4121
4065
|
return false;
|
|
4122
4066
|
}
|
|
4123
|
-
|
|
4067
|
+
logger5.error("Failed to delete conversation state", error, {
|
|
4124
4068
|
conversationId
|
|
4125
4069
|
});
|
|
4126
4070
|
throw error;
|
|
@@ -4137,12 +4081,12 @@ var FileStorage = class {
|
|
|
4137
4081
|
await fs4.mkdir(conversationDir, { recursive: true });
|
|
4138
4082
|
const logLine = JSON.stringify(log) + "\n";
|
|
4139
4083
|
await fs4.appendFile(interactionsFilePath, logLine, "utf-8");
|
|
4140
|
-
|
|
4084
|
+
logger5.debug("Interaction logged", {
|
|
4141
4085
|
conversationId: log.conversationId,
|
|
4142
4086
|
toolName: log.toolName
|
|
4143
4087
|
});
|
|
4144
4088
|
} catch (error) {
|
|
4145
|
-
|
|
4089
|
+
logger5.error("Failed to log interaction", error, {
|
|
4146
4090
|
conversationId: log.conversationId,
|
|
4147
4091
|
toolName: log.toolName
|
|
4148
4092
|
});
|
|
@@ -4164,7 +4108,7 @@ var FileStorage = class {
|
|
|
4164
4108
|
const log = JSON.parse(line);
|
|
4165
4109
|
logs.push(log);
|
|
4166
4110
|
} catch {
|
|
4167
|
-
|
|
4111
|
+
logger5.warn("Skipping corrupted interaction log line", {
|
|
4168
4112
|
conversationId
|
|
4169
4113
|
});
|
|
4170
4114
|
}
|
|
@@ -4174,7 +4118,7 @@ var FileStorage = class {
|
|
|
4174
4118
|
if (error.code === "ENOENT") {
|
|
4175
4119
|
return [];
|
|
4176
4120
|
}
|
|
4177
|
-
|
|
4121
|
+
logger5.error("Failed to get interaction logs", error, {
|
|
4178
4122
|
conversationId
|
|
4179
4123
|
});
|
|
4180
4124
|
throw error;
|
|
@@ -4194,12 +4138,12 @@ var FileStorage = class {
|
|
|
4194
4138
|
const interactionsFilePath = this.getInteractionsFilePath(conversationId);
|
|
4195
4139
|
try {
|
|
4196
4140
|
await fs4.unlink(interactionsFilePath);
|
|
4197
|
-
|
|
4141
|
+
logger5.debug("Interaction logs deleted", { conversationId });
|
|
4198
4142
|
} catch (error) {
|
|
4199
4143
|
if (error.code === "ENOENT") {
|
|
4200
4144
|
return;
|
|
4201
4145
|
}
|
|
4202
|
-
|
|
4146
|
+
logger5.warn("Failed to delete interaction logs", {
|
|
4203
4147
|
conversationId,
|
|
4204
4148
|
error: error.message
|
|
4205
4149
|
});
|
|
@@ -4218,13 +4162,13 @@ var FileStorage = class {
|
|
|
4218
4162
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4219
4163
|
};
|
|
4220
4164
|
await this.saveConversationState(updatedState);
|
|
4221
|
-
|
|
4165
|
+
logger5.debug("Conversation state reset", { conversationId });
|
|
4222
4166
|
}
|
|
4223
4167
|
/**
|
|
4224
4168
|
* Close file storage (no-op for file-based storage)
|
|
4225
4169
|
*/
|
|
4226
4170
|
async close() {
|
|
4227
|
-
|
|
4171
|
+
logger5.debug("FileStorage closed");
|
|
4228
4172
|
}
|
|
4229
4173
|
};
|
|
4230
4174
|
|
|
@@ -4236,7 +4180,7 @@ import { existsSync } from "fs";
|
|
|
4236
4180
|
// ../core/dist/path-validation-utils.js
|
|
4237
4181
|
import { access, stat } from "fs/promises";
|
|
4238
4182
|
import { resolve, isAbsolute, join as join2, normalize, basename } from "path";
|
|
4239
|
-
var
|
|
4183
|
+
var logger6 = createLogger("PathValidationUtils");
|
|
4240
4184
|
var PathValidationUtils = class {
|
|
4241
4185
|
/**
|
|
4242
4186
|
* Validate if a string is a known template name
|
|
@@ -4264,7 +4208,7 @@ var PathValidationUtils = class {
|
|
|
4264
4208
|
error: "Path points to a directory, not a file"
|
|
4265
4209
|
};
|
|
4266
4210
|
}
|
|
4267
|
-
|
|
4211
|
+
logger6.debug("File path validated successfully", {
|
|
4268
4212
|
originalPath: filePath,
|
|
4269
4213
|
resolvedPath
|
|
4270
4214
|
});
|
|
@@ -4274,7 +4218,7 @@ var PathValidationUtils = class {
|
|
|
4274
4218
|
};
|
|
4275
4219
|
} catch (error) {
|
|
4276
4220
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
4277
|
-
|
|
4221
|
+
logger6.debug("File path validation failed", {
|
|
4278
4222
|
filePath,
|
|
4279
4223
|
error: errorMessage
|
|
4280
4224
|
});
|
|
@@ -4304,7 +4248,7 @@ var PathValidationUtils = class {
|
|
|
4304
4248
|
error: "Path is neither a file nor a directory"
|
|
4305
4249
|
};
|
|
4306
4250
|
}
|
|
4307
|
-
|
|
4251
|
+
logger6.debug("File or directory path validated successfully", {
|
|
4308
4252
|
originalPath: filePath,
|
|
4309
4253
|
resolvedPath,
|
|
4310
4254
|
isFile: stats.isFile(),
|
|
@@ -4316,7 +4260,7 @@ var PathValidationUtils = class {
|
|
|
4316
4260
|
};
|
|
4317
4261
|
} catch (error) {
|
|
4318
4262
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
4319
|
-
|
|
4263
|
+
logger6.debug("File or directory path validation failed", {
|
|
4320
4264
|
filePath,
|
|
4321
4265
|
error: errorMessage
|
|
4322
4266
|
});
|
|
@@ -4431,7 +4375,7 @@ function getPathBasename(filePath, fallback = "unknown") {
|
|
|
4431
4375
|
import { writeFile, readFile, access as access2 } from "fs/promises";
|
|
4432
4376
|
import { dirname as dirname2 } from "path";
|
|
4433
4377
|
import { mkdir } from "fs/promises";
|
|
4434
|
-
var
|
|
4378
|
+
var logger7 = createLogger("PlanManager");
|
|
4435
4379
|
var PlanManager = class {
|
|
4436
4380
|
stateMachine = null;
|
|
4437
4381
|
/**
|
|
@@ -4439,7 +4383,7 @@ var PlanManager = class {
|
|
|
4439
4383
|
*/
|
|
4440
4384
|
setStateMachine(stateMachine) {
|
|
4441
4385
|
this.stateMachine = stateMachine;
|
|
4442
|
-
|
|
4386
|
+
logger7.debug("State machine set for plan manager", {
|
|
4443
4387
|
name: stateMachine.name,
|
|
4444
4388
|
phases: Object.keys(stateMachine.states)
|
|
4445
4389
|
});
|
|
@@ -4448,7 +4392,7 @@ var PlanManager = class {
|
|
|
4448
4392
|
* Set the task backend configuration
|
|
4449
4393
|
*/
|
|
4450
4394
|
setTaskBackend(taskBackend) {
|
|
4451
|
-
|
|
4395
|
+
logger7.debug("Task backend set for plan manager (markdown mode)", {
|
|
4452
4396
|
backend: taskBackend.backend,
|
|
4453
4397
|
available: taskBackend.isAvailable
|
|
4454
4398
|
});
|
|
@@ -4476,43 +4420,43 @@ var PlanManager = class {
|
|
|
4476
4420
|
* Create initial plan file if it doesn't exist
|
|
4477
4421
|
*/
|
|
4478
4422
|
async ensurePlanFile(planFilePath, projectPath, gitBranch) {
|
|
4479
|
-
|
|
4423
|
+
logger7.debug("Ensuring plan file exists", {
|
|
4480
4424
|
planFilePath,
|
|
4481
4425
|
projectPath,
|
|
4482
4426
|
gitBranch
|
|
4483
4427
|
});
|
|
4484
4428
|
const planInfo = await this.getPlanFileInfo(planFilePath);
|
|
4485
4429
|
if (!planInfo.exists) {
|
|
4486
|
-
|
|
4430
|
+
logger7.info("Plan file not found, creating initial plan", {
|
|
4487
4431
|
planFilePath
|
|
4488
4432
|
});
|
|
4489
4433
|
await this.createInitialPlanFile(planFilePath, projectPath, gitBranch);
|
|
4490
|
-
|
|
4434
|
+
logger7.info("Initial plan file created successfully", { planFilePath });
|
|
4491
4435
|
} else {
|
|
4492
|
-
|
|
4436
|
+
logger7.debug("Plan file already exists", { planFilePath });
|
|
4493
4437
|
}
|
|
4494
4438
|
}
|
|
4495
4439
|
/**
|
|
4496
4440
|
* Create initial plan file with template content
|
|
4497
4441
|
*/
|
|
4498
4442
|
async createInitialPlanFile(planFilePath, projectPath, gitBranch) {
|
|
4499
|
-
|
|
4443
|
+
logger7.debug("Creating initial plan file", { planFilePath });
|
|
4500
4444
|
try {
|
|
4501
4445
|
await mkdir(dirname2(planFilePath), { recursive: true });
|
|
4502
|
-
|
|
4446
|
+
logger7.debug("Plan file directory ensured", {
|
|
4503
4447
|
directory: dirname2(planFilePath)
|
|
4504
4448
|
});
|
|
4505
4449
|
const projectName = getPathBasename(projectPath, "Unknown Project");
|
|
4506
4450
|
const branchInfo = gitBranch !== "no-git" ? ` (${gitBranch} branch)` : "";
|
|
4507
4451
|
const initialContent = this.generateInitialPlanContent(projectName, branchInfo);
|
|
4508
4452
|
await writeFile(planFilePath, initialContent, "utf-8");
|
|
4509
|
-
|
|
4453
|
+
logger7.info("Initial plan file written successfully", {
|
|
4510
4454
|
planFilePath,
|
|
4511
4455
|
contentLength: initialContent.length,
|
|
4512
4456
|
projectName
|
|
4513
4457
|
});
|
|
4514
4458
|
} catch (error) {
|
|
4515
|
-
|
|
4459
|
+
logger7.error("Failed to create initial plan file", error, {
|
|
4516
4460
|
planFilePath
|
|
4517
4461
|
});
|
|
4518
4462
|
throw error;
|
|
@@ -4544,7 +4488,7 @@ var PlanManager = class {
|
|
|
4544
4488
|
*Additional context and observations*
|
|
4545
4489
|
|
|
4546
4490
|
`;
|
|
4547
|
-
content += `## ${
|
|
4491
|
+
content += `## ${capitalizePhase(initialPhase)}
|
|
4548
4492
|
### Tasks
|
|
4549
4493
|
- [ ] *Tasks will be added as they are identified*
|
|
4550
4494
|
|
|
@@ -4554,7 +4498,7 @@ var PlanManager = class {
|
|
|
4554
4498
|
`;
|
|
4555
4499
|
for (const phase of phases) {
|
|
4556
4500
|
if (phase !== initialPhase) {
|
|
4557
|
-
content += `## ${
|
|
4501
|
+
content += `## ${capitalizePhase(phase)}
|
|
4558
4502
|
### Tasks
|
|
4559
4503
|
- [ ] *To be added when this phase becomes active*
|
|
4560
4504
|
|
|
@@ -4606,31 +4550,31 @@ var PlanManager = class {
|
|
|
4606
4550
|
}
|
|
4607
4551
|
const phaseDefinition = this.stateMachine.states[phase];
|
|
4608
4552
|
if (!phaseDefinition) {
|
|
4609
|
-
|
|
4610
|
-
return `Update the ${
|
|
4553
|
+
logger7.warn("Unknown phase for plan file guidance", { phase });
|
|
4554
|
+
return `Update the ${capitalizePhase(phase)} section with current progress and mark completed tasks.`;
|
|
4611
4555
|
}
|
|
4612
|
-
const capitalizedPhase =
|
|
4556
|
+
const capitalizedPhase = capitalizePhase(phase);
|
|
4613
4557
|
return `Update the ${capitalizedPhase} section with progress. Mark completed tasks with [x] and add new tasks as they are identified.`;
|
|
4614
4558
|
}
|
|
4615
4559
|
/**
|
|
4616
4560
|
* Delete plan file
|
|
4617
4561
|
*/
|
|
4618
4562
|
async deletePlanFile(planFilePath) {
|
|
4619
|
-
|
|
4563
|
+
logger7.debug("Deleting plan file", { planFilePath });
|
|
4620
4564
|
try {
|
|
4621
4565
|
await access2(planFilePath);
|
|
4622
4566
|
const { unlink: unlink2 } = await import("fs/promises");
|
|
4623
4567
|
await unlink2(planFilePath);
|
|
4624
|
-
|
|
4568
|
+
logger7.info("Plan file deleted successfully", { planFilePath });
|
|
4625
4569
|
return true;
|
|
4626
4570
|
} catch (error) {
|
|
4627
4571
|
if (error.code === "ENOENT") {
|
|
4628
|
-
|
|
4572
|
+
logger7.debug("Plan file does not exist, nothing to delete", {
|
|
4629
4573
|
planFilePath
|
|
4630
4574
|
});
|
|
4631
4575
|
return true;
|
|
4632
4576
|
}
|
|
4633
|
-
|
|
4577
|
+
logger7.error("Failed to delete plan file", error, {
|
|
4634
4578
|
planFilePath
|
|
4635
4579
|
});
|
|
4636
4580
|
throw error;
|
|
@@ -4640,32 +4584,26 @@ var PlanManager = class {
|
|
|
4640
4584
|
* Ensure plan file is deleted (verify deletion)
|
|
4641
4585
|
*/
|
|
4642
4586
|
async ensurePlanFileDeleted(planFilePath) {
|
|
4643
|
-
|
|
4587
|
+
logger7.debug("Ensuring plan file is deleted", { planFilePath });
|
|
4644
4588
|
try {
|
|
4645
4589
|
await access2(planFilePath);
|
|
4646
|
-
|
|
4590
|
+
logger7.warn("Plan file still exists after deletion attempt", {
|
|
4647
4591
|
planFilePath
|
|
4648
4592
|
});
|
|
4649
4593
|
return false;
|
|
4650
4594
|
} catch (error) {
|
|
4651
4595
|
if (error.code === "ENOENT") {
|
|
4652
|
-
|
|
4596
|
+
logger7.debug("Plan file successfully deleted (does not exist)", {
|
|
4653
4597
|
planFilePath
|
|
4654
4598
|
});
|
|
4655
4599
|
return true;
|
|
4656
4600
|
}
|
|
4657
|
-
|
|
4601
|
+
logger7.error("Error checking plan file deletion", error, {
|
|
4658
4602
|
planFilePath
|
|
4659
4603
|
});
|
|
4660
4604
|
throw error;
|
|
4661
4605
|
}
|
|
4662
4606
|
}
|
|
4663
|
-
/**
|
|
4664
|
-
* Capitalize phase name for display
|
|
4665
|
-
*/
|
|
4666
|
-
capitalizePhase(phase) {
|
|
4667
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
4668
|
-
}
|
|
4669
4607
|
/**
|
|
4670
4608
|
* Generate workflow documentation URL for predefined workflows
|
|
4671
4609
|
* Returns undefined for custom workflows
|
|
@@ -4676,10 +4614,24 @@ var PlanManager = class {
|
|
|
4676
4614
|
}
|
|
4677
4615
|
return `https://mrsimpson.github.io/responsible-vibe-mcp/workflows/${workflowName}`;
|
|
4678
4616
|
}
|
|
4617
|
+
/**
|
|
4618
|
+
* Generate base instructions for the LLM after a workflow is started.
|
|
4619
|
+
* Instructs the LLM to populate the Goal section and define phase entrance
|
|
4620
|
+
* criteria in the freshly created plan file.
|
|
4621
|
+
*/
|
|
4622
|
+
getInitialPlanGuidance(planFilePath, workflowDocUrl) {
|
|
4623
|
+
const docInfo = workflowDocUrl ? `
|
|
4624
|
+
|
|
4625
|
+
Inform the user about the chosen workflow. They can visit: ${workflowDocUrl} to get detailed information.` : "";
|
|
4626
|
+
const i18nNote = `
|
|
4627
|
+
|
|
4628
|
+
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.`;
|
|
4629
|
+
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}`;
|
|
4630
|
+
}
|
|
4679
4631
|
};
|
|
4680
4632
|
|
|
4681
4633
|
// ../core/dist/conversation-manager.js
|
|
4682
|
-
var
|
|
4634
|
+
var logger8 = createLogger("ConversationManager");
|
|
4683
4635
|
var ConversationManager = class {
|
|
4684
4636
|
database;
|
|
4685
4637
|
projectPath;
|
|
@@ -4706,11 +4658,11 @@ var ConversationManager = class {
|
|
|
4706
4658
|
async getConversationContext() {
|
|
4707
4659
|
const projectPath = this.getProjectPath();
|
|
4708
4660
|
const gitBranch = this.getGitBranch(projectPath);
|
|
4709
|
-
|
|
4661
|
+
logger8.debug("Getting conversation context", { projectPath, gitBranch });
|
|
4710
4662
|
const conversationId = this.generateConversationId(projectPath, gitBranch);
|
|
4711
4663
|
const state = await this.database.getConversationState(conversationId);
|
|
4712
4664
|
if (!state) {
|
|
4713
|
-
|
|
4665
|
+
logger8.warn("No conversation found for context", {
|
|
4714
4666
|
projectPath,
|
|
4715
4667
|
gitBranch,
|
|
4716
4668
|
conversationId
|
|
@@ -4739,7 +4691,7 @@ var ConversationManager = class {
|
|
|
4739
4691
|
async createConversationContext(workflowName, projectPathOverride) {
|
|
4740
4692
|
const projectPath = projectPathOverride || this.getProjectPath();
|
|
4741
4693
|
const gitBranch = this.getGitBranch(projectPath);
|
|
4742
|
-
|
|
4694
|
+
logger8.debug("Creating conversation context", {
|
|
4743
4695
|
projectPath,
|
|
4744
4696
|
gitBranch,
|
|
4745
4697
|
workflowName
|
|
@@ -4749,14 +4701,14 @@ var ConversationManager = class {
|
|
|
4749
4701
|
if (existingState) {
|
|
4750
4702
|
if (existingState.workflowName !== workflowName) {
|
|
4751
4703
|
const errorMessage = `Development conversation already exists with workflow '${existingState.workflowName}'. Cannot change to '${workflowName}'. Use reset_development() first to start with a new workflow.`;
|
|
4752
|
-
|
|
4704
|
+
logger8.error("Attempted workflow change on existing conversation", new Error(errorMessage), {
|
|
4753
4705
|
existingWorkflow: existingState.workflowName,
|
|
4754
4706
|
requestedWorkflow: workflowName,
|
|
4755
4707
|
conversationId
|
|
4756
4708
|
});
|
|
4757
4709
|
throw new Error(errorMessage);
|
|
4758
4710
|
}
|
|
4759
|
-
|
|
4711
|
+
logger8.debug("Conversation already exists, returning existing context", {
|
|
4760
4712
|
conversationId
|
|
4761
4713
|
});
|
|
4762
4714
|
return {
|
|
@@ -4785,7 +4737,7 @@ var ConversationManager = class {
|
|
|
4785
4737
|
* @param updates - Partial state updates to apply
|
|
4786
4738
|
*/
|
|
4787
4739
|
async updateConversationState(conversationId, updates) {
|
|
4788
|
-
|
|
4740
|
+
logger8.debug("Updating conversation state", { conversationId, updates });
|
|
4789
4741
|
const currentState = await this.database.getConversationState(conversationId);
|
|
4790
4742
|
if (!currentState) {
|
|
4791
4743
|
throw new Error(`Conversation state not found for ID: ${conversationId}`);
|
|
@@ -4796,7 +4748,7 @@ var ConversationManager = class {
|
|
|
4796
4748
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4797
4749
|
};
|
|
4798
4750
|
await this.database.saveConversationState(updatedState);
|
|
4799
|
-
|
|
4751
|
+
logger8.info("Conversation state updated", {
|
|
4800
4752
|
conversationId,
|
|
4801
4753
|
currentPhase: updatedState.currentPhase
|
|
4802
4754
|
});
|
|
@@ -4809,7 +4761,7 @@ var ConversationManager = class {
|
|
|
4809
4761
|
* @param gitBranch - Git branch name
|
|
4810
4762
|
*/
|
|
4811
4763
|
async createNewConversationState(conversationId, projectPath, gitBranch, workflowName = "waterfall") {
|
|
4812
|
-
|
|
4764
|
+
logger8.info("Creating new conversation state", {
|
|
4813
4765
|
conversationId,
|
|
4814
4766
|
projectPath,
|
|
4815
4767
|
gitBranch
|
|
@@ -4833,7 +4785,7 @@ var ConversationManager = class {
|
|
|
4833
4785
|
updatedAt: timestamp2
|
|
4834
4786
|
};
|
|
4835
4787
|
await this.database.saveConversationState(newState);
|
|
4836
|
-
|
|
4788
|
+
logger8.info("New conversation state created", {
|
|
4837
4789
|
conversationId,
|
|
4838
4790
|
planFilePath,
|
|
4839
4791
|
initialPhase
|
|
@@ -4876,7 +4828,7 @@ var ConversationManager = class {
|
|
|
4876
4828
|
getGitBranch(projectPath) {
|
|
4877
4829
|
try {
|
|
4878
4830
|
if (!existsSync(`${projectPath}/.git`)) {
|
|
4879
|
-
|
|
4831
|
+
logger8.debug('Not a git repository, using "default" as branch name', {
|
|
4880
4832
|
projectPath
|
|
4881
4833
|
});
|
|
4882
4834
|
return "default";
|
|
@@ -4887,10 +4839,10 @@ var ConversationManager = class {
|
|
|
4887
4839
|
stdio: ["ignore", "pipe", "ignore"]
|
|
4888
4840
|
// Suppress stderr
|
|
4889
4841
|
}).trim();
|
|
4890
|
-
|
|
4842
|
+
logger8.debug("Detected git branch", { projectPath, branch });
|
|
4891
4843
|
return branch;
|
|
4892
4844
|
} catch (_error) {
|
|
4893
|
-
|
|
4845
|
+
logger8.debug('Failed to get git branch, using "default" as branch name', {
|
|
4894
4846
|
projectPath
|
|
4895
4847
|
});
|
|
4896
4848
|
return "default";
|
|
@@ -4904,13 +4856,13 @@ var ConversationManager = class {
|
|
|
4904
4856
|
try {
|
|
4905
4857
|
const interactions = await this.database.getInteractionsByConversationId(conversationId);
|
|
4906
4858
|
const count = interactions.length;
|
|
4907
|
-
|
|
4859
|
+
logger8.debug("Checked interaction count for conversation", {
|
|
4908
4860
|
conversationId,
|
|
4909
4861
|
count
|
|
4910
4862
|
});
|
|
4911
4863
|
return count > 0;
|
|
4912
4864
|
} catch (error) {
|
|
4913
|
-
|
|
4865
|
+
logger8.error("Failed to check interaction count", error, {
|
|
4914
4866
|
conversationId
|
|
4915
4867
|
});
|
|
4916
4868
|
return false;
|
|
@@ -4920,24 +4872,24 @@ var ConversationManager = class {
|
|
|
4920
4872
|
* Reset conversation data (hybrid approach)
|
|
4921
4873
|
*/
|
|
4922
4874
|
async resetConversation(confirm, reason) {
|
|
4923
|
-
|
|
4875
|
+
logger8.info("Starting conversation reset", { confirm, reason });
|
|
4924
4876
|
this.validateResetRequest(confirm);
|
|
4925
4877
|
const context = await this.getConversationContext();
|
|
4926
4878
|
const resetItems = [];
|
|
4927
4879
|
try {
|
|
4928
4880
|
await this.database.softDeleteInteractionLogs(context.conversationId);
|
|
4929
4881
|
resetItems.push("interaction_logs");
|
|
4930
|
-
|
|
4882
|
+
logger8.debug("Interaction logs soft deleted");
|
|
4931
4883
|
await this.database.deleteConversationState(context.conversationId);
|
|
4932
4884
|
resetItems.push("conversation_state");
|
|
4933
|
-
|
|
4885
|
+
logger8.debug("Conversation state hard deleted");
|
|
4934
4886
|
const planManager = new PlanManager();
|
|
4935
4887
|
await planManager.deletePlanFile(context.planFilePath);
|
|
4936
4888
|
resetItems.push("plan_file");
|
|
4937
|
-
|
|
4889
|
+
logger8.debug("Plan file deleted");
|
|
4938
4890
|
await this.verifyResetCleanup(context.conversationId, context.planFilePath);
|
|
4939
4891
|
const message = `Successfully reset conversation ${context.conversationId}. Reset items: ${resetItems.join(", ")}${reason ? `. Reason: ${reason}` : ""}`;
|
|
4940
|
-
|
|
4892
|
+
logger8.info("Conversation reset completed successfully", {
|
|
4941
4893
|
conversationId: context.conversationId,
|
|
4942
4894
|
resetItems,
|
|
4943
4895
|
reason
|
|
@@ -4949,7 +4901,7 @@ var ConversationManager = class {
|
|
|
4949
4901
|
message
|
|
4950
4902
|
};
|
|
4951
4903
|
} catch (error) {
|
|
4952
|
-
|
|
4904
|
+
logger8.error("Failed to reset conversation", error, {
|
|
4953
4905
|
conversationId: context.conversationId,
|
|
4954
4906
|
resetItems,
|
|
4955
4907
|
reason
|
|
@@ -4969,7 +4921,7 @@ var ConversationManager = class {
|
|
|
4969
4921
|
* Verify that reset cleanup was successful
|
|
4970
4922
|
*/
|
|
4971
4923
|
async verifyResetCleanup(conversationId, planFilePath) {
|
|
4972
|
-
|
|
4924
|
+
logger8.debug("Verifying reset cleanup", { conversationId, planFilePath });
|
|
4973
4925
|
try {
|
|
4974
4926
|
const state = await this.database.getConversationState(conversationId);
|
|
4975
4927
|
if (state) {
|
|
@@ -4980,9 +4932,9 @@ var ConversationManager = class {
|
|
|
4980
4932
|
if (!isDeleted) {
|
|
4981
4933
|
throw new Error("Plan file was not properly deleted");
|
|
4982
4934
|
}
|
|
4983
|
-
|
|
4935
|
+
logger8.debug("Reset cleanup verification successful");
|
|
4984
4936
|
} catch (error) {
|
|
4985
|
-
|
|
4937
|
+
logger8.error("Reset cleanup verification failed", error);
|
|
4986
4938
|
throw error;
|
|
4987
4939
|
}
|
|
4988
4940
|
}
|
|
@@ -4990,13 +4942,13 @@ var ConversationManager = class {
|
|
|
4990
4942
|
* Clean up conversation data (used internally)
|
|
4991
4943
|
*/
|
|
4992
4944
|
async cleanupConversationData(conversationId) {
|
|
4993
|
-
|
|
4945
|
+
logger8.debug("Cleaning up conversation data", { conversationId });
|
|
4994
4946
|
try {
|
|
4995
4947
|
await this.database.softDeleteInteractionLogs(conversationId);
|
|
4996
4948
|
await this.database.deleteConversationState(conversationId);
|
|
4997
|
-
|
|
4949
|
+
logger8.debug("Conversation data cleanup completed", { conversationId });
|
|
4998
4950
|
} catch (error) {
|
|
4999
|
-
|
|
4951
|
+
logger8.error("Failed to cleanup conversation data", error, {
|
|
5000
4952
|
conversationId
|
|
5001
4953
|
});
|
|
5002
4954
|
throw error;
|
|
@@ -5009,7 +4961,7 @@ import { readFile as readFile2, readdir, stat as stat2 } from "fs/promises";
|
|
|
5009
4961
|
import { join as join3, dirname as dirname3 } from "path";
|
|
5010
4962
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
5011
4963
|
import { createRequire as createRequire3 } from "module";
|
|
5012
|
-
var
|
|
4964
|
+
var logger9 = createLogger("TemplateManager");
|
|
5013
4965
|
var TemplateManager = class {
|
|
5014
4966
|
templatesPath;
|
|
5015
4967
|
constructor() {
|
|
@@ -5038,13 +4990,13 @@ var TemplateManager = class {
|
|
|
5038
4990
|
for (const strategy of strategies) {
|
|
5039
4991
|
try {
|
|
5040
4992
|
__require("fs").accessSync(strategy);
|
|
5041
|
-
|
|
4993
|
+
logger9.debug("Using templates path", { path: strategy });
|
|
5042
4994
|
return strategy;
|
|
5043
4995
|
} catch (_error) {
|
|
5044
4996
|
}
|
|
5045
4997
|
}
|
|
5046
4998
|
const fallback = strategies[0];
|
|
5047
|
-
|
|
4999
|
+
logger9.warn("No templates directory found, using fallback", {
|
|
5048
5000
|
fallback,
|
|
5049
5001
|
strategies
|
|
5050
5002
|
});
|
|
@@ -5098,7 +5050,7 @@ var TemplateManager = class {
|
|
|
5098
5050
|
const content = await readFile2(templateFilePath, "utf-8");
|
|
5099
5051
|
return { content };
|
|
5100
5052
|
} catch (error) {
|
|
5101
|
-
|
|
5053
|
+
logger9.error(`Failed to load template: ${type2}/${template}`, error);
|
|
5102
5054
|
throw new Error(`Template not found: ${type2}/${template}. Tried: ${templatePath} (directory) and ${templateFilePath} (file)`);
|
|
5103
5055
|
}
|
|
5104
5056
|
}
|
|
@@ -5179,16 +5131,16 @@ var TemplateManager = class {
|
|
|
5179
5131
|
}
|
|
5180
5132
|
templates.sort();
|
|
5181
5133
|
} catch (error) {
|
|
5182
|
-
|
|
5134
|
+
logger9.warn(`Failed to scan templates for type: ${type2}`, {
|
|
5183
5135
|
typePath,
|
|
5184
5136
|
error: error instanceof Error ? error.message : String(error)
|
|
5185
5137
|
});
|
|
5186
5138
|
}
|
|
5187
5139
|
}
|
|
5188
|
-
|
|
5140
|
+
logger9.debug("Discovered available templates", result);
|
|
5189
5141
|
return result;
|
|
5190
5142
|
} catch (error) {
|
|
5191
|
-
|
|
5143
|
+
logger9.error("Failed to discover templates", error);
|
|
5192
5144
|
return result;
|
|
5193
5145
|
}
|
|
5194
5146
|
}
|
|
@@ -5197,12 +5149,14 @@ var TemplateManager = class {
|
|
|
5197
5149
|
// ../core/dist/project-docs-manager.js
|
|
5198
5150
|
import { writeFile as writeFile2, access as access3, mkdir as mkdir2, unlink, symlink, lstat, stat as stat3, readdir as readdir2 } from "fs/promises";
|
|
5199
5151
|
import { join as join4, dirname as dirname4, relative, extname, basename as basename2 } from "path";
|
|
5200
|
-
var
|
|
5152
|
+
var defaultLogger2 = createLogger("ProjectDocsManager");
|
|
5201
5153
|
var ProjectDocsManager = class {
|
|
5202
5154
|
templateManager;
|
|
5203
5155
|
// Make public for access from other classes
|
|
5204
|
-
|
|
5156
|
+
logger;
|
|
5157
|
+
constructor(logger14 = defaultLogger2) {
|
|
5205
5158
|
this.templateManager = new TemplateManager();
|
|
5159
|
+
this.logger = logger14;
|
|
5206
5160
|
}
|
|
5207
5161
|
/**
|
|
5208
5162
|
* Get project docs directory path
|
|
@@ -5373,7 +5327,7 @@ var ProjectDocsManager = class {
|
|
|
5373
5327
|
} else {
|
|
5374
5328
|
skipped.push("design.md");
|
|
5375
5329
|
}
|
|
5376
|
-
|
|
5330
|
+
this.logger.info("Project docs creation/linking completed", {
|
|
5377
5331
|
created,
|
|
5378
5332
|
linked,
|
|
5379
5333
|
skipped,
|
|
@@ -5392,13 +5346,13 @@ var ProjectDocsManager = class {
|
|
|
5392
5346
|
const targetDir = dirname4(targetPath);
|
|
5393
5347
|
const relativePath = relative(targetDir, sourcePath);
|
|
5394
5348
|
await symlink(relativePath, targetPath);
|
|
5395
|
-
|
|
5349
|
+
this.logger.debug("Symlink created successfully", {
|
|
5396
5350
|
sourcePath,
|
|
5397
5351
|
targetPath,
|
|
5398
5352
|
relativePath
|
|
5399
5353
|
});
|
|
5400
5354
|
} catch (error) {
|
|
5401
|
-
|
|
5355
|
+
this.logger.error("Failed to create symlink", error, {
|
|
5402
5356
|
sourcePath,
|
|
5403
5357
|
targetPath
|
|
5404
5358
|
});
|
|
@@ -5412,14 +5366,14 @@ var ProjectDocsManager = class {
|
|
|
5412
5366
|
try {
|
|
5413
5367
|
const stats = await lstat(documentPath);
|
|
5414
5368
|
await unlink(documentPath);
|
|
5415
|
-
|
|
5369
|
+
this.logger.debug("Existing document removed", {
|
|
5416
5370
|
documentPath,
|
|
5417
5371
|
wasSymlink: stats.isSymbolicLink()
|
|
5418
5372
|
});
|
|
5419
5373
|
} catch (error) {
|
|
5420
5374
|
const nodeError = error;
|
|
5421
5375
|
if (error instanceof Error && "code" in nodeError && nodeError.code !== "ENOENT") {
|
|
5422
|
-
|
|
5376
|
+
this.logger.debug("Failed to remove existing document", {
|
|
5423
5377
|
documentPath,
|
|
5424
5378
|
error: nodeError.message
|
|
5425
5379
|
});
|
|
@@ -5441,9 +5395,9 @@ var ProjectDocsManager = class {
|
|
|
5441
5395
|
await writeFile2(filePath, file.content.toString());
|
|
5442
5396
|
}
|
|
5443
5397
|
}
|
|
5444
|
-
|
|
5398
|
+
this.logger.debug(`Created ${type2} document`, { documentPath, template });
|
|
5445
5399
|
} catch (error) {
|
|
5446
|
-
|
|
5400
|
+
this.logger.error(`Failed to create ${type2} document`, error, {
|
|
5447
5401
|
documentPath,
|
|
5448
5402
|
template
|
|
5449
5403
|
});
|
|
@@ -5514,7 +5468,7 @@ var ProjectDocsManager = class {
|
|
|
5514
5468
|
// ../core/dist/file-detection-manager.js
|
|
5515
5469
|
import { readdir as readdir3, access as access4 } from "fs/promises";
|
|
5516
5470
|
import { join as join5, basename as basename3 } from "path";
|
|
5517
|
-
var
|
|
5471
|
+
var logger10 = createLogger("FileDetectionManager");
|
|
5518
5472
|
var FileDetectionManager = class {
|
|
5519
5473
|
projectPath;
|
|
5520
5474
|
constructor(projectPath) {
|
|
@@ -5524,7 +5478,7 @@ var FileDetectionManager = class {
|
|
|
5524
5478
|
* Detect existing documentation files in the project
|
|
5525
5479
|
*/
|
|
5526
5480
|
async detectDocumentationFiles() {
|
|
5527
|
-
|
|
5481
|
+
logger10.debug("Starting documentation file detection", {
|
|
5528
5482
|
projectPath: this.projectPath
|
|
5529
5483
|
});
|
|
5530
5484
|
const searchLocations = this.getSearchLocations();
|
|
@@ -5550,7 +5504,7 @@ var FileDetectionManager = class {
|
|
|
5550
5504
|
}
|
|
5551
5505
|
}
|
|
5552
5506
|
} catch (error) {
|
|
5553
|
-
|
|
5507
|
+
logger10.debug("Search location not accessible", {
|
|
5554
5508
|
location,
|
|
5555
5509
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
5556
5510
|
});
|
|
@@ -5559,7 +5513,7 @@ var FileDetectionManager = class {
|
|
|
5559
5513
|
result.architecture = this.sortAndDeduplicate(result.architecture);
|
|
5560
5514
|
result.requirements = this.sortAndDeduplicate(result.requirements);
|
|
5561
5515
|
result.design = this.sortAndDeduplicate(result.design);
|
|
5562
|
-
|
|
5516
|
+
logger10.info("Documentation file detection completed", {
|
|
5563
5517
|
found: {
|
|
5564
5518
|
architecture: result.architecture.length,
|
|
5565
5519
|
requirements: result.requirements.length,
|
|
@@ -5604,7 +5558,7 @@ var FileDetectionManager = class {
|
|
|
5604
5558
|
}
|
|
5605
5559
|
return files;
|
|
5606
5560
|
} catch (error) {
|
|
5607
|
-
|
|
5561
|
+
logger10.debug("Failed to scan location", {
|
|
5608
5562
|
location,
|
|
5609
5563
|
error: error instanceof Error ? error.message : "Unknown error"
|
|
5610
5564
|
});
|
|
@@ -5681,43 +5635,27 @@ var FileDetectionManager = class {
|
|
|
5681
5635
|
* Format file suggestions for LLM responses
|
|
5682
5636
|
*/
|
|
5683
5637
|
formatSuggestions(detectionResult) {
|
|
5684
|
-
const
|
|
5638
|
+
const found = [];
|
|
5685
5639
|
if (detectionResult.architecture.length > 0) {
|
|
5686
|
-
|
|
5687
|
-
for (const file of detectionResult.architecture.slice(0, 3)) {
|
|
5688
|
-
suggestions.push(` - ${file.relativePath} (${file.confidence} confidence)`);
|
|
5689
|
-
}
|
|
5640
|
+
found.push(`architecture: ${detectionResult.architecture.slice(0, 2).map((f) => f.relativePath).join(", ")}`);
|
|
5690
5641
|
}
|
|
5691
5642
|
if (detectionResult.requirements.length > 0) {
|
|
5692
|
-
|
|
5693
|
-
for (const file of detectionResult.requirements.slice(0, 3)) {
|
|
5694
|
-
suggestions.push(` - ${file.relativePath} (${file.confidence} confidence)`);
|
|
5695
|
-
}
|
|
5643
|
+
found.push(`requirements: ${detectionResult.requirements.slice(0, 2).map((f) => f.relativePath).join(", ")}`);
|
|
5696
5644
|
}
|
|
5697
5645
|
if (detectionResult.design.length > 0) {
|
|
5698
|
-
|
|
5699
|
-
for (const file of detectionResult.design.slice(0, 3)) {
|
|
5700
|
-
suggestions.push(` - ${file.relativePath} (${file.confidence} confidence)`);
|
|
5701
|
-
}
|
|
5646
|
+
found.push(`design: ${detectionResult.design.slice(0, 2).map((f) => f.relativePath).join(", ")}`);
|
|
5702
5647
|
}
|
|
5703
|
-
if (
|
|
5648
|
+
if (found.length === 0) {
|
|
5704
5649
|
return "No existing documentation files detected.";
|
|
5705
5650
|
}
|
|
5706
|
-
return
|
|
5707
|
-
"Existing documentation files detected:",
|
|
5708
|
-
"",
|
|
5709
|
-
...suggestions,
|
|
5710
|
-
"",
|
|
5711
|
-
"You can use these files with `setup_project_docs` by providing the file paths instead of template names.",
|
|
5712
|
-
'Example: `setup_project_docs({ architecture: "README.md", requirements: "docs/requirements.md", design: "freestyle" })`'
|
|
5713
|
-
].join("\n");
|
|
5651
|
+
return `Found: ${found.join("; ")}. Link existing files via \`setup_project_docs({ architecture: "path/to/file.md" })\` or use template names.`;
|
|
5714
5652
|
}
|
|
5715
5653
|
};
|
|
5716
5654
|
|
|
5717
5655
|
// ../core/dist/git-manager.js
|
|
5718
5656
|
import { execSync as execSync2 } from "child_process";
|
|
5719
5657
|
import { existsSync as existsSync2 } from "fs";
|
|
5720
|
-
var
|
|
5658
|
+
var logger11 = createLogger("GitManager");
|
|
5721
5659
|
var GitManager = class {
|
|
5722
5660
|
/**
|
|
5723
5661
|
* Check if a directory is a git repository
|
|
@@ -5731,7 +5669,7 @@ var GitManager = class {
|
|
|
5731
5669
|
static getCurrentBranch(projectPath) {
|
|
5732
5670
|
try {
|
|
5733
5671
|
if (!this.isGitRepository(projectPath)) {
|
|
5734
|
-
|
|
5672
|
+
logger11.debug('Not a git repository, using "default" as branch name', {
|
|
5735
5673
|
projectPath
|
|
5736
5674
|
});
|
|
5737
5675
|
return "default";
|
|
@@ -5741,10 +5679,10 @@ var GitManager = class {
|
|
|
5741
5679
|
encoding: "utf-8",
|
|
5742
5680
|
stdio: ["ignore", "pipe", "ignore"]
|
|
5743
5681
|
}).trim();
|
|
5744
|
-
|
|
5682
|
+
logger11.debug("Detected git branch", { projectPath, branch });
|
|
5745
5683
|
return branch;
|
|
5746
5684
|
} catch (_error) {
|
|
5747
|
-
|
|
5685
|
+
logger11.debug('Failed to get git branch, using "default" as branch name', {
|
|
5748
5686
|
projectPath
|
|
5749
5687
|
});
|
|
5750
5688
|
return "default";
|
|
@@ -5765,7 +5703,7 @@ var GitManager = class {
|
|
|
5765
5703
|
}).trim();
|
|
5766
5704
|
return hash;
|
|
5767
5705
|
} catch (error) {
|
|
5768
|
-
|
|
5706
|
+
logger11.debug("Failed to get current commit hash", { projectPath, error });
|
|
5769
5707
|
return null;
|
|
5770
5708
|
}
|
|
5771
5709
|
}
|
|
@@ -5775,7 +5713,7 @@ var GitManager = class {
|
|
|
5775
5713
|
static createCommit(message, projectPath) {
|
|
5776
5714
|
try {
|
|
5777
5715
|
if (!this.isGitRepository(projectPath)) {
|
|
5778
|
-
|
|
5716
|
+
logger11.debug("Not a git repository, skipping commit", { projectPath });
|
|
5779
5717
|
return false;
|
|
5780
5718
|
}
|
|
5781
5719
|
execSync2("git add .", {
|
|
@@ -5788,10 +5726,10 @@ var GitManager = class {
|
|
|
5788
5726
|
encoding: "utf-8",
|
|
5789
5727
|
stdio: ["ignore", "pipe", "ignore"]
|
|
5790
5728
|
});
|
|
5791
|
-
|
|
5729
|
+
logger11.debug("Created commit successfully", { projectPath, message });
|
|
5792
5730
|
return true;
|
|
5793
5731
|
} catch (error) {
|
|
5794
|
-
|
|
5732
|
+
logger11.debug("Failed to create commit", {
|
|
5795
5733
|
projectPath,
|
|
5796
5734
|
message,
|
|
5797
5735
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -5805,7 +5743,7 @@ var GitManager = class {
|
|
|
5805
5743
|
static hasUncommittedChanges(projectPath) {
|
|
5806
5744
|
try {
|
|
5807
5745
|
if (!this.isGitRepository(projectPath)) {
|
|
5808
|
-
|
|
5746
|
+
logger11.debug("Not a git repository, no uncommitted changes", {
|
|
5809
5747
|
projectPath
|
|
5810
5748
|
});
|
|
5811
5749
|
return false;
|
|
@@ -5816,13 +5754,13 @@ var GitManager = class {
|
|
|
5816
5754
|
stdio: ["ignore", "pipe", "ignore"]
|
|
5817
5755
|
}).trim();
|
|
5818
5756
|
const hasChanges = status.length > 0;
|
|
5819
|
-
|
|
5757
|
+
logger11.debug("Checked for uncommitted changes", {
|
|
5820
5758
|
projectPath,
|
|
5821
5759
|
hasChanges
|
|
5822
5760
|
});
|
|
5823
5761
|
return hasChanges;
|
|
5824
5762
|
} catch (error) {
|
|
5825
|
-
|
|
5763
|
+
logger11.debug("Failed to check for uncommitted changes", {
|
|
5826
5764
|
projectPath,
|
|
5827
5765
|
error: error instanceof Error ? error.message : String(error)
|
|
5828
5766
|
});
|
|
@@ -5833,7 +5771,7 @@ var GitManager = class {
|
|
|
5833
5771
|
|
|
5834
5772
|
// ../core/dist/task-backend.js
|
|
5835
5773
|
import { execSync as execSync3 } from "child_process";
|
|
5836
|
-
var
|
|
5774
|
+
var defaultLogger3 = createLogger("TaskBackend");
|
|
5837
5775
|
var TaskBackendManager = class _TaskBackendManager {
|
|
5838
5776
|
/**
|
|
5839
5777
|
* Detect and validate the requested task backend
|
|
@@ -5845,8 +5783,9 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5845
5783
|
* When TASK_BACKEND is explicitly set:
|
|
5846
5784
|
* - Uses the specified backend (markdown or beads)
|
|
5847
5785
|
* - For beads, validates availability and provides setup instructions if not available
|
|
5786
|
+
*
|
|
5848
5787
|
*/
|
|
5849
|
-
static detectTaskBackend() {
|
|
5788
|
+
static detectTaskBackend(logger14 = defaultLogger3) {
|
|
5850
5789
|
const envBackend = process.env["TASK_BACKEND"]?.toLowerCase().trim();
|
|
5851
5790
|
if (envBackend && !["markdown", "beads"].includes(envBackend)) {
|
|
5852
5791
|
logger14.debug("Invalid TASK_BACKEND value, treating as not set", {
|
|
@@ -5854,9 +5793,9 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5854
5793
|
});
|
|
5855
5794
|
}
|
|
5856
5795
|
if (!envBackend || !["markdown", "beads"].includes(envBackend)) {
|
|
5857
|
-
const beadsAvailable2 = _TaskBackendManager.checkBeadsAvailability();
|
|
5796
|
+
const beadsAvailable2 = _TaskBackendManager.checkBeadsAvailability(logger14);
|
|
5858
5797
|
if (beadsAvailable2.isAvailable) {
|
|
5859
|
-
logger14.
|
|
5798
|
+
logger14.debug("Auto-detected beads backend (bd command available)", {
|
|
5860
5799
|
reason: "TASK_BACKEND not set, bd command found"
|
|
5861
5800
|
});
|
|
5862
5801
|
return {
|
|
@@ -5880,7 +5819,7 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5880
5819
|
isAvailable: true
|
|
5881
5820
|
};
|
|
5882
5821
|
}
|
|
5883
|
-
const beadsAvailable = _TaskBackendManager.checkBeadsAvailability();
|
|
5822
|
+
const beadsAvailable = _TaskBackendManager.checkBeadsAvailability(logger14);
|
|
5884
5823
|
if (beadsAvailable.isAvailable) {
|
|
5885
5824
|
logger14.debug("Using explicitly configured beads backend");
|
|
5886
5825
|
return {
|
|
@@ -5897,7 +5836,7 @@ var TaskBackendManager = class _TaskBackendManager {
|
|
|
5897
5836
|
/**
|
|
5898
5837
|
* Check if beads command is available and functional
|
|
5899
5838
|
*/
|
|
5900
|
-
static checkBeadsAvailability() {
|
|
5839
|
+
static checkBeadsAvailability(logger14 = defaultLogger3) {
|
|
5901
5840
|
try {
|
|
5902
5841
|
const output = execSync3("bd --version", {
|
|
5903
5842
|
encoding: "utf-8",
|
|
@@ -5973,9 +5912,10 @@ export TASK_BACKEND=markdown
|
|
|
5973
5912
|
}
|
|
5974
5913
|
/**
|
|
5975
5914
|
* Validate task backend configuration and throw error if invalid
|
|
5915
|
+
*
|
|
5976
5916
|
*/
|
|
5977
|
-
static validateTaskBackend() {
|
|
5978
|
-
const config = this.detectTaskBackend();
|
|
5917
|
+
static validateTaskBackend(logger14 = defaultLogger3) {
|
|
5918
|
+
const config = this.detectTaskBackend(logger14);
|
|
5979
5919
|
if (!config.isAvailable) {
|
|
5980
5920
|
const setupInstructions = config.backend === "beads" ? this.getBeadsSetupInstructions() : "Task backend validation failed";
|
|
5981
5921
|
throw new Error(`Task backend '${config.backend}' is not available.
|
|
@@ -5994,11 +5934,13 @@ ${setupInstructions}`);
|
|
|
5994
5934
|
|
|
5995
5935
|
// ../core/dist/beads-integration.js
|
|
5996
5936
|
import { execSync as execSync4 } from "child_process";
|
|
5997
|
-
var
|
|
5937
|
+
var defaultLogger4 = createLogger("BeadsIntegration");
|
|
5998
5938
|
var BeadsIntegration = class {
|
|
5999
5939
|
projectPath;
|
|
6000
|
-
|
|
5940
|
+
logger;
|
|
5941
|
+
constructor(projectPath, logger14 = defaultLogger4) {
|
|
6001
5942
|
this.projectPath = projectPath;
|
|
5943
|
+
this.logger = logger14;
|
|
6002
5944
|
}
|
|
6003
5945
|
/**
|
|
6004
5946
|
* Ensure beads is initialized in the project directory
|
|
@@ -6014,7 +5956,7 @@ var BeadsIntegration = class {
|
|
|
6014
5956
|
} catch (error) {
|
|
6015
5957
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6016
5958
|
if (errorMessage.includes("not initialized") || errorMessage.includes("no database") || errorMessage.includes("init")) {
|
|
6017
|
-
|
|
5959
|
+
this.logger.info("Beads not initialized, running bd init --no-db", {
|
|
6018
5960
|
projectPath: this.projectPath
|
|
6019
5961
|
});
|
|
6020
5962
|
try {
|
|
@@ -6023,12 +5965,12 @@ var BeadsIntegration = class {
|
|
|
6023
5965
|
encoding: "utf-8",
|
|
6024
5966
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6025
5967
|
});
|
|
6026
|
-
|
|
5968
|
+
this.logger.info("Successfully initialized beads in project", {
|
|
6027
5969
|
projectPath: this.projectPath
|
|
6028
5970
|
});
|
|
6029
5971
|
} catch (initError) {
|
|
6030
5972
|
const initErrorMessage = initError instanceof Error ? initError.message : String(initError);
|
|
6031
|
-
|
|
5973
|
+
this.logger.error("Failed to initialize beads", initError instanceof Error ? initError : new Error(initErrorMessage), { projectPath: this.projectPath });
|
|
6032
5974
|
throw new Error(`Failed to initialize beads: ${initErrorMessage}`);
|
|
6033
5975
|
}
|
|
6034
5976
|
} else {
|
|
@@ -6046,7 +5988,7 @@ var BeadsIntegration = class {
|
|
|
6046
5988
|
const epicDescription = description || `Responsible vibe engineering session using ${workflowName} workflow for ${projectName}`;
|
|
6047
5989
|
const priority = 2;
|
|
6048
5990
|
const command = `bd create "${epicTitle}" --description "${epicDescription}" --priority ${priority}`;
|
|
6049
|
-
|
|
5991
|
+
this.logger.debug("Creating beads project epic", {
|
|
6050
5992
|
command,
|
|
6051
5993
|
projectName,
|
|
6052
5994
|
workflowName,
|
|
@@ -6060,7 +6002,7 @@ var BeadsIntegration = class {
|
|
|
6060
6002
|
});
|
|
6061
6003
|
const match = output.match(/✓ Created issue: ([\w\d.-]+)/) || output.match(/Created issue: ([\w\d.-]+)/) || output.match(/Created (bd-[\w\d.]+)/);
|
|
6062
6004
|
if (!match) {
|
|
6063
|
-
|
|
6005
|
+
this.logger.warn("Failed to extract task ID from beads output", {
|
|
6064
6006
|
command: `bd create "${epicTitle}" --description "${epicDescription}" --priority 2`,
|
|
6065
6007
|
output: output.slice(0, 200)
|
|
6066
6008
|
// Truncated for logging
|
|
@@ -6068,7 +6010,7 @@ var BeadsIntegration = class {
|
|
|
6068
6010
|
throw new Error(`Failed to extract task ID from beads output: ${output.slice(0, 100)}...`);
|
|
6069
6011
|
}
|
|
6070
6012
|
const epicId = match[1] || "";
|
|
6071
|
-
|
|
6013
|
+
this.logger.info("Created beads project epic", {
|
|
6072
6014
|
epicId,
|
|
6073
6015
|
epicTitle,
|
|
6074
6016
|
projectPath: this.projectPath
|
|
@@ -6082,10 +6024,10 @@ var BeadsIntegration = class {
|
|
|
6082
6024
|
workflowName,
|
|
6083
6025
|
projectPath: this.projectPath
|
|
6084
6026
|
};
|
|
6085
|
-
|
|
6027
|
+
this.logger.error("Failed to create beads project epic", error instanceof Error ? error : new Error(errorMessage), commandInfo);
|
|
6086
6028
|
const execError = error;
|
|
6087
6029
|
if (execError?.stderr) {
|
|
6088
|
-
|
|
6030
|
+
this.logger.error("Beads command stderr output", new Error("Command stderr"), {
|
|
6089
6031
|
stderr: execError.stderr.toString(),
|
|
6090
6032
|
...commandInfo
|
|
6091
6033
|
});
|
|
@@ -6101,12 +6043,12 @@ var BeadsIntegration = class {
|
|
|
6101
6043
|
const phaseTasks = [];
|
|
6102
6044
|
const phaseNames = Object.keys(phases);
|
|
6103
6045
|
for (const phase of phaseNames) {
|
|
6104
|
-
const phaseTitle =
|
|
6046
|
+
const phaseTitle = capitalizePhase(phase);
|
|
6105
6047
|
const priority = 3;
|
|
6106
6048
|
const stateDefinition = phases[phase];
|
|
6107
6049
|
const description = (stateDefinition?.default_instructions || `${workflowName} workflow ${phase} phase tasks`).replace(/"/g, '\\"').replace(/\n/g, " ").replace(/\r/g, "").trim();
|
|
6108
6050
|
const command = `bd create "${phaseTitle}" --description "${description}" --parent ${epicId} --priority ${priority}`;
|
|
6109
|
-
|
|
6051
|
+
this.logger.debug("Creating beads phase task", {
|
|
6110
6052
|
command,
|
|
6111
6053
|
phase,
|
|
6112
6054
|
epicId,
|
|
@@ -6120,7 +6062,7 @@ var BeadsIntegration = class {
|
|
|
6120
6062
|
});
|
|
6121
6063
|
const match = output.match(/✓ Created issue: ([\w\d.-]+)/) || output.match(/Created issue: ([\w\d.-]+)/) || output.match(/Created (bd-[\w\d.]+)/);
|
|
6122
6064
|
if (!match) {
|
|
6123
|
-
|
|
6065
|
+
this.logger.warn("Failed to extract phase task ID from beads output", {
|
|
6124
6066
|
command,
|
|
6125
6067
|
output: output.slice(0, 200)
|
|
6126
6068
|
// Truncated for logging
|
|
@@ -6133,7 +6075,7 @@ var BeadsIntegration = class {
|
|
|
6133
6075
|
phaseName: phaseTitle,
|
|
6134
6076
|
taskId: phaseTaskId
|
|
6135
6077
|
});
|
|
6136
|
-
|
|
6078
|
+
this.logger.debug("Created beads phase task", {
|
|
6137
6079
|
phase,
|
|
6138
6080
|
phaseTaskId,
|
|
6139
6081
|
epicId,
|
|
@@ -6147,10 +6089,10 @@ var BeadsIntegration = class {
|
|
|
6147
6089
|
epicId,
|
|
6148
6090
|
projectPath: this.projectPath
|
|
6149
6091
|
};
|
|
6150
|
-
|
|
6092
|
+
this.logger.error("Failed to create beads phase task", error instanceof Error ? error : new Error(errorMessage), commandInfo);
|
|
6151
6093
|
const execError = error;
|
|
6152
6094
|
if (execError?.stderr) {
|
|
6153
|
-
|
|
6095
|
+
this.logger.error("Beads phase command stderr output", new Error("Command stderr"), {
|
|
6154
6096
|
stderr: execError.stderr.toString(),
|
|
6155
6097
|
...commandInfo
|
|
6156
6098
|
});
|
|
@@ -6158,7 +6100,7 @@ var BeadsIntegration = class {
|
|
|
6158
6100
|
throw new Error(`Failed to create beads phase task for ${phase}: ${errorMessage}`);
|
|
6159
6101
|
}
|
|
6160
6102
|
}
|
|
6161
|
-
|
|
6103
|
+
this.logger.info("Created all beads phase tasks", {
|
|
6162
6104
|
count: phaseTasks.length,
|
|
6163
6105
|
epicId,
|
|
6164
6106
|
projectPath: this.projectPath
|
|
@@ -6171,13 +6113,13 @@ var BeadsIntegration = class {
|
|
|
6171
6113
|
*/
|
|
6172
6114
|
async createPhaseDependencies(phaseTasks) {
|
|
6173
6115
|
if (phaseTasks.length < 2) {
|
|
6174
|
-
|
|
6116
|
+
this.logger.debug("Skipping phase dependencies - less than 2 phases", {
|
|
6175
6117
|
phaseCount: phaseTasks.length,
|
|
6176
6118
|
projectPath: this.projectPath
|
|
6177
6119
|
});
|
|
6178
6120
|
return;
|
|
6179
6121
|
}
|
|
6180
|
-
|
|
6122
|
+
this.logger.info("Creating sequential phase dependencies", {
|
|
6181
6123
|
phaseCount: phaseTasks.length,
|
|
6182
6124
|
projectPath: this.projectPath
|
|
6183
6125
|
});
|
|
@@ -6186,7 +6128,7 @@ var BeadsIntegration = class {
|
|
|
6186
6128
|
const currentPhase = phaseTasks[i];
|
|
6187
6129
|
const nextPhase = phaseTasks[i + 1];
|
|
6188
6130
|
if (!currentPhase || !nextPhase) {
|
|
6189
|
-
|
|
6131
|
+
this.logger.warn("Skipping phase dependency - missing phase data", {
|
|
6190
6132
|
currentPhaseIndex: i,
|
|
6191
6133
|
nextPhaseIndex: i + 1,
|
|
6192
6134
|
totalPhases: phaseTasks.length,
|
|
@@ -6200,7 +6142,7 @@ var BeadsIntegration = class {
|
|
|
6200
6142
|
continue;
|
|
6201
6143
|
}
|
|
6202
6144
|
const command = `bd dep ${currentPhase.taskId} --blocks ${nextPhase.taskId}`;
|
|
6203
|
-
|
|
6145
|
+
this.logger.debug("Creating phase dependency", {
|
|
6204
6146
|
command,
|
|
6205
6147
|
currentPhase: currentPhase.phaseName,
|
|
6206
6148
|
nextPhase: nextPhase.phaseName,
|
|
@@ -6214,14 +6156,14 @@ var BeadsIntegration = class {
|
|
|
6214
6156
|
encoding: "utf-8",
|
|
6215
6157
|
stdio: ["ignore", "pipe", "pipe"]
|
|
6216
6158
|
});
|
|
6217
|
-
|
|
6159
|
+
this.logger.debug("Successfully created phase dependency", {
|
|
6218
6160
|
currentPhase: currentPhase.phaseName,
|
|
6219
6161
|
nextPhase: nextPhase.phaseName,
|
|
6220
6162
|
projectPath: this.projectPath
|
|
6221
6163
|
});
|
|
6222
6164
|
} catch (error) {
|
|
6223
6165
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6224
|
-
|
|
6166
|
+
this.logger.warn("Failed to create phase dependency - continuing anyway", {
|
|
6225
6167
|
error: errorMessage,
|
|
6226
6168
|
command,
|
|
6227
6169
|
currentPhase: currentPhase.phaseName,
|
|
@@ -6230,7 +6172,7 @@ var BeadsIntegration = class {
|
|
|
6230
6172
|
});
|
|
6231
6173
|
const execError = error;
|
|
6232
6174
|
if (execError?.stderr) {
|
|
6233
|
-
|
|
6175
|
+
this.logger.debug("Beads dependency command stderr", {
|
|
6234
6176
|
stderr: execError.stderr.toString(),
|
|
6235
6177
|
command,
|
|
6236
6178
|
projectPath: this.projectPath
|
|
@@ -6244,25 +6186,19 @@ var BeadsIntegration = class {
|
|
|
6244
6186
|
}
|
|
6245
6187
|
}
|
|
6246
6188
|
if (failedDependencies.length > 0) {
|
|
6247
|
-
|
|
6189
|
+
this.logger.warn("Some phase dependencies could not be created - app continues without these dependencies", {
|
|
6248
6190
|
failedCount: failedDependencies.length,
|
|
6249
6191
|
failedDependencies,
|
|
6250
6192
|
projectPath: this.projectPath
|
|
6251
6193
|
});
|
|
6252
6194
|
}
|
|
6253
|
-
|
|
6195
|
+
this.logger.info("Completed phase dependency creation", {
|
|
6254
6196
|
dependencyCount: phaseTasks.length - 1,
|
|
6255
6197
|
successCount: phaseTasks.length - 1 - failedDependencies.length,
|
|
6256
6198
|
failedCount: failedDependencies.length,
|
|
6257
6199
|
projectPath: this.projectPath
|
|
6258
6200
|
});
|
|
6259
6201
|
}
|
|
6260
|
-
/**
|
|
6261
|
-
* Capitalize phase name for display
|
|
6262
|
-
*/
|
|
6263
|
-
capitalizePhase(phase) {
|
|
6264
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
6265
|
-
}
|
|
6266
6202
|
/**
|
|
6267
6203
|
* Validate parameters for epic creation
|
|
6268
6204
|
*/
|
|
@@ -6310,11 +6246,13 @@ var BeadsIntegration = class {
|
|
|
6310
6246
|
// ../core/dist/beads-state-manager.js
|
|
6311
6247
|
import { writeFile as writeFile3, readFile as readFile3, mkdir as mkdir3, access as access5 } from "fs/promises";
|
|
6312
6248
|
import { join as join6, dirname as dirname5 } from "path";
|
|
6313
|
-
var
|
|
6249
|
+
var defaultLogger5 = createLogger("BeadsStateManager");
|
|
6314
6250
|
var BeadsStateManager = class {
|
|
6315
6251
|
projectPath;
|
|
6316
|
-
|
|
6252
|
+
logger;
|
|
6253
|
+
constructor(projectPath, logger14 = defaultLogger5) {
|
|
6317
6254
|
this.projectPath = projectPath;
|
|
6255
|
+
this.logger = logger14;
|
|
6318
6256
|
}
|
|
6319
6257
|
/**
|
|
6320
6258
|
* Get the path to the beads state file for a conversation
|
|
@@ -6335,7 +6273,7 @@ var BeadsStateManager = class {
|
|
|
6335
6273
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6336
6274
|
};
|
|
6337
6275
|
await this.saveState(state);
|
|
6338
|
-
|
|
6276
|
+
this.logger.info("Created beads conversation state", {
|
|
6339
6277
|
conversationId,
|
|
6340
6278
|
epicId,
|
|
6341
6279
|
phaseCount: phaseTasks.length,
|
|
@@ -6352,7 +6290,7 @@ var BeadsStateManager = class {
|
|
|
6352
6290
|
await access5(statePath);
|
|
6353
6291
|
const content = await readFile3(statePath, "utf-8");
|
|
6354
6292
|
const state = JSON.parse(content);
|
|
6355
|
-
|
|
6293
|
+
this.logger.debug("Retrieved beads conversation state", {
|
|
6356
6294
|
conversationId,
|
|
6357
6295
|
epicId: state.epicId,
|
|
6358
6296
|
phaseCount: state.phaseTasks.length,
|
|
@@ -6361,14 +6299,14 @@ var BeadsStateManager = class {
|
|
|
6361
6299
|
return state;
|
|
6362
6300
|
} catch (error) {
|
|
6363
6301
|
if (error.code === "ENOENT") {
|
|
6364
|
-
|
|
6302
|
+
this.logger.debug("No beads state found for conversation", {
|
|
6365
6303
|
conversationId,
|
|
6366
6304
|
projectPath: this.projectPath
|
|
6367
6305
|
});
|
|
6368
6306
|
return null;
|
|
6369
6307
|
}
|
|
6370
6308
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6371
|
-
|
|
6309
|
+
this.logger.warn("Failed to read beads state file", {
|
|
6372
6310
|
error: errorMessage,
|
|
6373
6311
|
conversationId,
|
|
6374
6312
|
statePath,
|
|
@@ -6387,7 +6325,7 @@ var BeadsStateManager = class {
|
|
|
6387
6325
|
}
|
|
6388
6326
|
const phaseTask = state.phaseTasks.find((task) => task.phaseId === phase);
|
|
6389
6327
|
if (phaseTask) {
|
|
6390
|
-
|
|
6328
|
+
this.logger.debug("Found phase task ID", {
|
|
6391
6329
|
conversationId,
|
|
6392
6330
|
phase,
|
|
6393
6331
|
taskId: phaseTask.taskId,
|
|
@@ -6395,7 +6333,7 @@ var BeadsStateManager = class {
|
|
|
6395
6333
|
});
|
|
6396
6334
|
return phaseTask.taskId;
|
|
6397
6335
|
}
|
|
6398
|
-
|
|
6336
|
+
this.logger.debug("No task ID found for phase", {
|
|
6399
6337
|
conversationId,
|
|
6400
6338
|
phase,
|
|
6401
6339
|
availablePhases: state.phaseTasks.map((t) => t.phaseId),
|
|
@@ -6409,7 +6347,7 @@ var BeadsStateManager = class {
|
|
|
6409
6347
|
async updateState(conversationId, updates) {
|
|
6410
6348
|
const existingState = await this.getState(conversationId);
|
|
6411
6349
|
if (!existingState) {
|
|
6412
|
-
|
|
6350
|
+
this.logger.warn("Cannot update non-existent beads state", {
|
|
6413
6351
|
conversationId,
|
|
6414
6352
|
projectPath: this.projectPath
|
|
6415
6353
|
});
|
|
@@ -6423,7 +6361,7 @@ var BeadsStateManager = class {
|
|
|
6423
6361
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
6424
6362
|
};
|
|
6425
6363
|
await this.saveState(updatedState);
|
|
6426
|
-
|
|
6364
|
+
this.logger.info("Updated beads conversation state", {
|
|
6427
6365
|
conversationId,
|
|
6428
6366
|
updatedFields: Object.keys(updates),
|
|
6429
6367
|
projectPath: this.projectPath
|
|
@@ -6438,21 +6376,21 @@ var BeadsStateManager = class {
|
|
|
6438
6376
|
try {
|
|
6439
6377
|
await access5(statePath);
|
|
6440
6378
|
await writeFile3(statePath + ".backup", await readFile3(statePath));
|
|
6441
|
-
|
|
6379
|
+
this.logger.info("Cleaned up beads conversation state", {
|
|
6442
6380
|
conversationId,
|
|
6443
6381
|
statePath,
|
|
6444
6382
|
projectPath: this.projectPath
|
|
6445
6383
|
});
|
|
6446
6384
|
} catch (error) {
|
|
6447
6385
|
if (error.code === "ENOENT") {
|
|
6448
|
-
|
|
6386
|
+
this.logger.debug("No beads state to clean up", {
|
|
6449
6387
|
conversationId,
|
|
6450
6388
|
projectPath: this.projectPath
|
|
6451
6389
|
});
|
|
6452
6390
|
return;
|
|
6453
6391
|
}
|
|
6454
6392
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6455
|
-
|
|
6393
|
+
this.logger.warn("Failed to clean up beads state", {
|
|
6456
6394
|
error: errorMessage,
|
|
6457
6395
|
conversationId,
|
|
6458
6396
|
statePath,
|
|
@@ -6482,7 +6420,7 @@ var BeadsStateManager = class {
|
|
|
6482
6420
|
await mkdir3(stateDir, { recursive: true });
|
|
6483
6421
|
const content = JSON.stringify(state, null, 2);
|
|
6484
6422
|
await writeFile3(statePath, content, "utf-8");
|
|
6485
|
-
|
|
6423
|
+
this.logger.debug("Saved beads state to file", {
|
|
6486
6424
|
conversationId: state.conversationId,
|
|
6487
6425
|
statePath,
|
|
6488
6426
|
fileSize: content.length,
|
|
@@ -6490,7 +6428,7 @@ var BeadsStateManager = class {
|
|
|
6490
6428
|
});
|
|
6491
6429
|
} catch (error) {
|
|
6492
6430
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6493
|
-
|
|
6431
|
+
this.logger.error("Failed to save beads state", error instanceof Error ? error : new Error(errorMessage), {
|
|
6494
6432
|
conversationId: state.conversationId,
|
|
6495
6433
|
statePath,
|
|
6496
6434
|
projectPath: this.projectPath
|
|
@@ -6501,7 +6439,7 @@ var BeadsStateManager = class {
|
|
|
6501
6439
|
};
|
|
6502
6440
|
|
|
6503
6441
|
// ../core/dist/interaction-logger.js
|
|
6504
|
-
var
|
|
6442
|
+
var logger12 = createLogger("InteractionLogger");
|
|
6505
6443
|
var InteractionLogger = class {
|
|
6506
6444
|
database;
|
|
6507
6445
|
/**
|
|
@@ -6511,7 +6449,7 @@ var InteractionLogger = class {
|
|
|
6511
6449
|
*/
|
|
6512
6450
|
constructor(database) {
|
|
6513
6451
|
this.database = database;
|
|
6514
|
-
|
|
6452
|
+
logger12.debug("InteractionLogger initialized");
|
|
6515
6453
|
}
|
|
6516
6454
|
/**
|
|
6517
6455
|
* Log an interaction with a tool
|
|
@@ -6524,7 +6462,7 @@ var InteractionLogger = class {
|
|
|
6524
6462
|
* @returns Promise that resolves when the log is saved
|
|
6525
6463
|
*/
|
|
6526
6464
|
async logInteraction(conversationId, toolName, inputParams, responseData, currentPhase) {
|
|
6527
|
-
|
|
6465
|
+
logger12.debug("Logging interaction", {
|
|
6528
6466
|
conversationId,
|
|
6529
6467
|
toolName,
|
|
6530
6468
|
currentPhase
|
|
@@ -6540,13 +6478,13 @@ var InteractionLogger = class {
|
|
|
6540
6478
|
timestamp: timestamp2
|
|
6541
6479
|
};
|
|
6542
6480
|
await this.database.logInteraction(log);
|
|
6543
|
-
|
|
6481
|
+
logger12.info("Interaction logged successfully", {
|
|
6544
6482
|
conversationId,
|
|
6545
6483
|
toolName,
|
|
6546
6484
|
timestamp: timestamp2
|
|
6547
6485
|
});
|
|
6548
6486
|
} catch (error) {
|
|
6549
|
-
|
|
6487
|
+
logger12.error("Failed to log interaction", error, {
|
|
6550
6488
|
conversationId,
|
|
6551
6489
|
toolName
|
|
6552
6490
|
});
|
|
@@ -6559,16 +6497,16 @@ var InteractionLogger = class {
|
|
|
6559
6497
|
* @returns Promise that resolves to an array of interaction logs
|
|
6560
6498
|
*/
|
|
6561
6499
|
async getInteractionsByConversationId(conversationId) {
|
|
6562
|
-
|
|
6500
|
+
logger12.debug("Getting interactions by conversation ID", { conversationId });
|
|
6563
6501
|
try {
|
|
6564
6502
|
const logs = await this.database.getInteractionsByConversationId(conversationId);
|
|
6565
|
-
|
|
6503
|
+
logger12.info("Retrieved interaction logs", {
|
|
6566
6504
|
conversationId,
|
|
6567
6505
|
count: logs.length
|
|
6568
6506
|
});
|
|
6569
6507
|
return logs;
|
|
6570
6508
|
} catch (error) {
|
|
6571
|
-
|
|
6509
|
+
logger12.error("Failed to get interaction logs", error, {
|
|
6572
6510
|
conversationId
|
|
6573
6511
|
});
|
|
6574
6512
|
throw error;
|
|
@@ -6579,11 +6517,11 @@ var InteractionLogger = class {
|
|
|
6579
6517
|
// ../core/dist/instruction-generator.js
|
|
6580
6518
|
var InstructionGenerator = class {
|
|
6581
6519
|
projectDocsManager;
|
|
6582
|
-
constructor(
|
|
6583
|
-
this.projectDocsManager = new ProjectDocsManager();
|
|
6520
|
+
constructor(logger14 = createLogger("InstructionGenerator")) {
|
|
6521
|
+
this.projectDocsManager = new ProjectDocsManager(logger14);
|
|
6584
6522
|
}
|
|
6585
6523
|
/**
|
|
6586
|
-
*
|
|
6524
|
+
* No-op: all phase context is provided per-call via InstructionContext.
|
|
6587
6525
|
*/
|
|
6588
6526
|
setStateMachine(_stateMachine) {
|
|
6589
6527
|
return;
|
|
@@ -6596,7 +6534,6 @@ var InstructionGenerator = class {
|
|
|
6596
6534
|
const enhancedInstructions = await this.enhanceInstructions(substitutedInstructions, context);
|
|
6597
6535
|
return {
|
|
6598
6536
|
instructions: enhancedInstructions,
|
|
6599
|
-
planFileGuidance: "Task management guidance is now included in main instructions",
|
|
6600
6537
|
metadata: {
|
|
6601
6538
|
phase: context.phase,
|
|
6602
6539
|
planFilePath: context.conversationContext.planFilePath,
|
|
@@ -6627,43 +6564,36 @@ var InstructionGenerator = class {
|
|
|
6627
6564
|
* Enhance base instructions with context-specific information
|
|
6628
6565
|
*/
|
|
6629
6566
|
async enhanceInstructions(baseInstructions, context) {
|
|
6630
|
-
const { phase, conversationContext,
|
|
6631
|
-
const phaseName =
|
|
6567
|
+
const { phase, conversationContext, allowedFilePatterns } = context;
|
|
6568
|
+
const phaseName = capitalizePhase(phase);
|
|
6632
6569
|
let workflowSection = `---
|
|
6633
|
-
**
|
|
6634
|
-
|
|
6635
|
-
-
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
|
|
6640
|
-
|
|
6641
|
-
workflowSection += "\n\nCall `whats_next()` after each user message.";
|
|
6570
|
+
**Read \`${conversationContext.planFilePath}\`** for context.
|
|
6571
|
+
- Focus on "${phaseName}" tasks, log decisions in "Key Decisions"
|
|
6572
|
+
- Do NOT use other task/todo tools - use only the plan file for task tracking`;
|
|
6573
|
+
if (allowedFilePatterns && allowedFilePatterns.length > 0 && !allowedFilePatterns.includes("**/*") && !allowedFilePatterns.includes("*")) {
|
|
6574
|
+
workflowSection += `
|
|
6575
|
+
- Files allowed: \`${allowedFilePatterns.join("`, `")}\``;
|
|
6576
|
+
}
|
|
6577
|
+
workflowSection += "\n\nCall `whats_next()` after user messages.";
|
|
6642
6578
|
return `## ${phaseName} Phase
|
|
6643
6579
|
|
|
6644
6580
|
${baseInstructions}
|
|
6645
6581
|
|
|
6646
6582
|
${workflowSection}`;
|
|
6647
6583
|
}
|
|
6648
|
-
/**
|
|
6649
|
-
* Capitalize phase name for display
|
|
6650
|
-
*/
|
|
6651
|
-
capitalizePhase(phase) {
|
|
6652
|
-
return phase.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
6653
|
-
}
|
|
6654
6584
|
};
|
|
6655
6585
|
|
|
6656
6586
|
// ../core/dist/system-prompt-generator.js
|
|
6657
|
-
var
|
|
6587
|
+
var logger13 = createLogger("SystemPromptGenerator");
|
|
6658
6588
|
function generateSystemPrompt(stateMachine) {
|
|
6659
|
-
|
|
6589
|
+
logger13.debug("Generating system prompt from state machine definition", {
|
|
6660
6590
|
stateMachineName: stateMachine.name,
|
|
6661
6591
|
phaseCount: Object.keys(stateMachine.states).length
|
|
6662
6592
|
});
|
|
6663
6593
|
return generateSimpleSystemPrompt(stateMachine);
|
|
6664
6594
|
}
|
|
6665
6595
|
function generateSimpleSystemPrompt(_stateMachine) {
|
|
6666
|
-
|
|
6596
|
+
logger13.debug("Generating system prompt");
|
|
6667
6597
|
const systemPrompt = `
|
|
6668
6598
|
You are an AI assistant that helps users develop software features using the workflows server.
|
|
6669
6599
|
|
|
@@ -6674,7 +6604,7 @@ Each tool call returns a JSON response with an "instructions" field. Follow thes
|
|
|
6674
6604
|
Use the development plan which you will retrieve via whats_next() to record important insights and decisions as per the structure of the plan.
|
|
6675
6605
|
|
|
6676
6606
|
Do not use your own task management tools.`;
|
|
6677
|
-
|
|
6607
|
+
logger13.info("System prompt generated successfully", {
|
|
6678
6608
|
promptLength: systemPrompt.length
|
|
6679
6609
|
});
|
|
6680
6610
|
return systemPrompt;
|
|
@@ -6688,13 +6618,16 @@ export {
|
|
|
6688
6618
|
isModeledTransition,
|
|
6689
6619
|
getContinuePhaseInstructions,
|
|
6690
6620
|
LogLevel,
|
|
6691
|
-
|
|
6692
|
-
|
|
6621
|
+
registerLogSink,
|
|
6622
|
+
clearLogSink,
|
|
6623
|
+
setLoggingLevel,
|
|
6624
|
+
setLoggingLevelFromString,
|
|
6693
6625
|
createLogger,
|
|
6694
6626
|
logger,
|
|
6695
6627
|
StateMachineLoader,
|
|
6696
6628
|
ConfigManager,
|
|
6697
6629
|
WorkflowManager,
|
|
6630
|
+
capitalizePhase,
|
|
6698
6631
|
TransitionEngine,
|
|
6699
6632
|
FileStorage,
|
|
6700
6633
|
PathValidationUtils,
|