wogiflow 2.4.2 → 2.4.3
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/.claude/docs/claude-code-compatibility.md +27 -0
- package/.claude/settings.json +1 -1
- package/.workflow/models/registry.json +1 -1
- package/package.json +4 -4
- package/scripts/MEMORY-ARCHITECTURE.md +1 -1
- package/scripts/base-workflow-step.js +136 -0
- package/scripts/flow-adaptive-learning.js +8 -9
- package/scripts/flow-aggregate.js +11 -6
- package/scripts/flow-api-index.js +4 -6
- package/scripts/flow-assumption-detector.js +0 -2
- package/scripts/flow-audit.js +15 -2
- package/scripts/flow-auto-context.js +8 -12
- package/scripts/flow-auto-learn.js +49 -49
- package/scripts/flow-background.js +5 -6
- package/scripts/flow-bridge-state.js +8 -10
- package/scripts/flow-bulk-loop.js +1 -3
- package/scripts/flow-bulk-orchestrator.js +1 -3
- package/scripts/flow-cascade-completion.js +0 -2
- package/scripts/flow-cascade.js +4 -4
- package/scripts/flow-checkpoint.js +10 -13
- package/scripts/flow-code-intelligence.js +10 -12
- package/scripts/flow-community-sync.js +4 -4
- package/scripts/flow-community.js +12 -20
- package/scripts/flow-config-defaults.js +0 -2
- package/scripts/flow-config-interactive.js +9 -5
- package/scripts/flow-config-loader.js +49 -92
- package/scripts/flow-config-substitution.js +0 -2
- package/scripts/flow-context-estimator.js +4 -4
- package/scripts/flow-context-init.js +10 -12
- package/scripts/flow-context-manager.js +0 -2
- package/scripts/flow-context-scoring.js +2 -2
- package/scripts/flow-contract-scan.js +6 -9
- package/scripts/flow-correct.js +29 -27
- package/scripts/flow-correction-detector.js +5 -1
- package/scripts/flow-damage-control.js +47 -54
- package/scripts/flow-decisions-merge.js +4 -14
- package/scripts/flow-diff.js +5 -8
- package/scripts/flow-done-gates.js +786 -0
- package/scripts/flow-done-report.js +123 -0
- package/scripts/flow-done.js +71 -717
- package/scripts/flow-entropy-monitor.js +1 -3
- package/scripts/flow-eval.js +5 -5
- package/scripts/flow-extraction-review.js +1 -0
- package/scripts/flow-failure-categories.js +0 -2
- package/scripts/flow-figma-confirm.js +5 -9
- package/scripts/flow-figma-generate.js +8 -10
- package/scripts/flow-figma-index.js +8 -10
- package/scripts/flow-figma-match.js +3 -5
- package/scripts/flow-figma-mcp-server.js +2 -4
- package/scripts/flow-figma-orchestrator.js +2 -3
- package/scripts/flow-figma-registry.js +2 -3
- package/scripts/flow-framework-resolver.js +0 -2
- package/scripts/flow-function-index.js +4 -6
- package/scripts/flow-gate-confidence.js +2 -2
- package/scripts/flow-gitignore.js +0 -2
- package/scripts/flow-guided-edit.js +5 -6
- package/scripts/flow-health.js +5 -6
- package/scripts/flow-hook-errors.js +6 -0
- package/scripts/flow-hook-status.js +263 -0
- package/scripts/flow-hooks.js +17 -29
- package/scripts/flow-http-client.js +9 -8
- package/scripts/flow-hybrid-interactive.js +7 -12
- package/scripts/flow-hybrid-test.js +12 -13
- package/scripts/flow-instruction-richness.js +1 -1
- package/scripts/flow-io.js +21 -4
- package/scripts/flow-knowledge-router.js +9 -3
- package/scripts/flow-learning-orchestrator.js +318 -13
- package/scripts/flow-links.js +5 -7
- package/scripts/flow-long-input-association.js +275 -0
- package/scripts/flow-long-input-chunking.js +1 -0
- package/scripts/flow-long-input-cli.js +0 -2
- package/scripts/flow-long-input-complexity.js +0 -2
- package/scripts/flow-long-input-constants.js +0 -2
- package/scripts/flow-long-input-contradictions.js +351 -0
- package/scripts/flow-long-input-detection.js +0 -2
- package/scripts/flow-long-input-passes.js +885 -0
- package/scripts/flow-long-input-stories.js +1 -1
- package/scripts/flow-long-input-voice.js +0 -2
- package/scripts/flow-long-input.js +425 -3005
- package/scripts/flow-loop-retry-learning.js +2 -3
- package/scripts/flow-lsp.js +3 -3
- package/scripts/flow-mcp-docs.js +3 -4
- package/scripts/flow-memory-db.js +6 -8
- package/scripts/flow-memory-sync.js +18 -11
- package/scripts/flow-metrics.js +1 -2
- package/scripts/flow-model-adapter.js +2 -3
- package/scripts/flow-model-config.js +72 -104
- package/scripts/flow-model-router.js +2 -2
- package/scripts/flow-model-types.js +0 -2
- package/scripts/flow-multi-approach.js +5 -6
- package/scripts/flow-orchestrate-context.js +3 -7
- package/scripts/flow-orchestrate-rollback.js +3 -8
- package/scripts/flow-orchestrate-state.js +8 -14
- package/scripts/flow-orchestrate-templates.js +2 -6
- package/scripts/flow-orchestrate-validator.js +5 -9
- package/scripts/flow-orchestrate.js +126 -103
- package/scripts/flow-output.js +0 -2
- package/scripts/flow-parallel.js +1 -1
- package/scripts/flow-paths.js +23 -2
- package/scripts/flow-pattern-enforcer.js +30 -28
- package/scripts/flow-pattern-extractor.js +3 -4
- package/scripts/flow-pending.js +0 -2
- package/scripts/flow-permissions.js +2 -3
- package/scripts/flow-plugin-registry.js +10 -12
- package/scripts/flow-prd-manager.js +1 -1
- package/scripts/flow-progress.js +7 -9
- package/scripts/flow-prompt-composer.js +3 -3
- package/scripts/flow-prompt-template.js +2 -2
- package/scripts/flow-providers.js +7 -4
- package/scripts/flow-registry-manager.js +7 -12
- package/scripts/flow-regression.js +9 -11
- package/scripts/flow-roadmap.js +2 -2
- package/scripts/flow-run-trace.js +16 -15
- package/scripts/flow-safety.js +2 -5
- package/scripts/flow-scanner-base.js +5 -7
- package/scripts/flow-scenario-engine.js +1 -5
- package/scripts/flow-security.js +29 -0
- package/scripts/flow-session-end.js +32 -41
- package/scripts/flow-session-learning.js +53 -49
- package/scripts/flow-setup-hooks.js +2 -3
- package/scripts/flow-skill-create.js +7 -12
- package/scripts/flow-skill-generator.js +12 -16
- package/scripts/flow-skill-learn.js +17 -8
- package/scripts/flow-skill-matcher.js +1 -2
- package/scripts/flow-spec-generator.js +2 -4
- package/scripts/flow-stack-wizard.js +5 -7
- package/scripts/flow-standards-learner.js +35 -16
- package/scripts/flow-start.js +2 -0
- package/scripts/flow-stats-collector.js +2 -2
- package/scripts/flow-status.js +10 -10
- package/scripts/flow-statusline-setup.js +2 -2
- package/scripts/flow-step-changelog.js +2 -3
- package/scripts/flow-step-comments.js +66 -81
- package/scripts/flow-step-complexity.js +50 -70
- package/scripts/flow-step-coverage.js +3 -5
- package/scripts/flow-step-knowledge.js +2 -3
- package/scripts/flow-step-pr-tests.js +64 -74
- package/scripts/flow-step-regression.js +3 -5
- package/scripts/flow-step-review.js +86 -103
- package/scripts/flow-step-security.js +111 -121
- package/scripts/flow-step-silent-failures.js +56 -83
- package/scripts/flow-step-simplifier.js +52 -70
- package/scripts/flow-story.js +4 -7
- package/scripts/flow-strict-adherence.js +3 -4
- package/scripts/flow-task-checkpoint.js +36 -5
- package/scripts/flow-task-enforcer.js +2 -24
- package/scripts/flow-tech-debt.js +1 -1
- package/scripts/flow-template-extractor.js +1 -0
- package/scripts/flow-templates.js +11 -13
- package/scripts/flow-test-api.js +9 -13
- package/scripts/flow-test-discovery.js +1 -1
- package/scripts/flow-test-generate.js +5 -9
- package/scripts/flow-test-integrity.js +3 -7
- package/scripts/flow-test-ui.js +5 -9
- package/scripts/flow-testing-deps.js +1 -3
- package/scripts/flow-tiered-learning.js +4 -4
- package/scripts/flow-todowrite-sync.js +1 -1
- package/scripts/flow-tokens.js +0 -2
- package/scripts/flow-verification-profile.js +6 -10
- package/scripts/flow-verify.js +12 -16
- package/scripts/flow-version-check.js +4 -12
- package/scripts/flow-webmcp-generator.js +3 -5
- package/scripts/flow-workflow-steps.js +0 -2
- package/scripts/flow-workflow.js +9 -11
- package/scripts/hooks/adapters/claude-code.js +2 -0
- package/scripts/hooks/core/config-change.js +1 -0
- package/scripts/hooks/core/extension-registry.js +0 -2
- package/scripts/hooks/core/instructions-loaded.js +1 -1
- package/scripts/hooks/core/observation-capture.js +5 -5
- package/scripts/hooks/core/phase-gate.js +5 -0
- package/scripts/hooks/core/post-compact.js +1 -12
- package/scripts/hooks/core/research-gate.js +2 -12
- package/scripts/hooks/core/routing-gate.js +6 -0
- package/scripts/hooks/core/task-completed.js +12 -0
- package/scripts/hooks/core/worktree-lifecycle.js +1 -1
- package/scripts/hooks/entry/claude-code/config-change.js +6 -29
- package/scripts/hooks/entry/claude-code/instructions-loaded.js +5 -30
- package/scripts/hooks/entry/claude-code/post-compact.js +4 -31
- package/scripts/hooks/entry/claude-code/post-tool-use.js +121 -172
- package/scripts/hooks/entry/claude-code/pre-tool-use.js +260 -361
- package/scripts/hooks/entry/claude-code/session-end.js +4 -28
- package/scripts/hooks/entry/claude-code/session-start.js +205 -243
- package/scripts/hooks/entry/claude-code/setup.js +8 -49
- package/scripts/hooks/entry/claude-code/stop.js +40 -72
- package/scripts/hooks/entry/claude-code/task-completed.js +4 -28
- package/scripts/hooks/entry/claude-code/user-prompt-submit.js +113 -195
- package/scripts/hooks/entry/claude-code/worktree-create.js +6 -25
- package/scripts/hooks/entry/claude-code/worktree-remove.js +6 -25
- package/scripts/hooks/entry/shared/hook-runner.js +99 -0
- package/scripts/hooks/entry/shared/read-stdin.js +0 -2
- package/scripts/registries/api-registry.js +0 -2
- package/scripts/registries/component-registry.js +5 -9
- package/scripts/registries/contract-scanner.js +2 -9
- package/scripts/registries/function-registry.js +0 -2
- package/scripts/registries/schema-registry.js +14 -18
- package/scripts/registries/service-registry.js +23 -27
|
@@ -15,11 +15,10 @@
|
|
|
15
15
|
|
|
16
16
|
const fs = require('node:fs');
|
|
17
17
|
const path = require('node:path');
|
|
18
|
-
const { getConfig, getProjectRoot, colors, readJson, info, success } = require('./flow-utils');
|
|
18
|
+
const { getConfig, getProjectRoot, colors, readJson, info, success, PATHS } = require('./flow-utils');
|
|
19
19
|
const { FailureCategory, detectCategory } = require('./flow-failure-categories');
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
const LEARNING_LOG_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'adaptive-learning.json');
|
|
21
|
+
const LEARNING_LOG_PATH = path.join(PATHS.state, 'adaptive-learning.json');
|
|
23
22
|
|
|
24
23
|
// ============================================================================
|
|
25
24
|
// Root Cause Categories
|
package/scripts/flow-lsp.js
CHANGED
|
@@ -327,7 +327,7 @@ class LSPClient {
|
|
|
327
327
|
});
|
|
328
328
|
|
|
329
329
|
// Wait a bit for the server to process
|
|
330
|
-
await
|
|
330
|
+
await require('node:timers/promises').setTimeout(100);
|
|
331
331
|
|
|
332
332
|
return uri;
|
|
333
333
|
}
|
|
@@ -419,7 +419,7 @@ class LSPClient {
|
|
|
419
419
|
const uri = await this.openDocument(filePath);
|
|
420
420
|
|
|
421
421
|
// Wait for diagnostics to be pushed
|
|
422
|
-
await
|
|
422
|
+
await require('node:timers/promises').setTimeout(500);
|
|
423
423
|
|
|
424
424
|
const diagnostics = this.diagnosticsCache.get(uri) || [];
|
|
425
425
|
|
|
@@ -916,7 +916,7 @@ module.exports = {
|
|
|
916
916
|
};
|
|
917
917
|
|
|
918
918
|
if (require.main === module) {
|
|
919
|
-
main().catch(
|
|
919
|
+
main().catch(err => {
|
|
920
920
|
error(err.message);
|
|
921
921
|
process.exit(1);
|
|
922
922
|
});
|
package/scripts/flow-mcp-docs.js
CHANGED
|
@@ -27,9 +27,8 @@ const { color, printHeader, printSection, success } = require('./flow-output');;
|
|
|
27
27
|
// Configuration
|
|
28
28
|
// ============================================================
|
|
29
29
|
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const DOCS_OUTPUT_PATH = path.join(PROJECT_ROOT, '.claude', 'docs', 'knowledge-base', '05-development-tools', 'mcp-tools-generated.md');
|
|
30
|
+
const MCP_DOCS_PATH = path.join(PATHS.state, 'mcp-tools.json');
|
|
31
|
+
const DOCS_OUTPUT_PATH = path.join(PATHS.root, '.claude', 'docs', 'knowledge-base', '05-development-tools', 'mcp-tools-generated.md');
|
|
33
32
|
|
|
34
33
|
// Known MCP server locations in this project
|
|
35
34
|
const MCP_SERVER_PATHS = [
|
|
@@ -46,7 +45,7 @@ const MCP_SERVER_PATHS = [
|
|
|
46
45
|
* @returns {Object[]} Array of tool definitions
|
|
47
46
|
*/
|
|
48
47
|
function extractToolsFromFile(filePath) {
|
|
49
|
-
const fullPath = path.join(
|
|
48
|
+
const fullPath = path.join(PATHS.root, filePath);
|
|
50
49
|
|
|
51
50
|
if (!fileExists(fullPath)) {
|
|
52
51
|
return [];
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Features:
|
|
12
12
|
* - SQLite database with sql.js
|
|
13
|
-
* - Embeddings via @
|
|
13
|
+
* - Embeddings via @huggingface/transformers
|
|
14
14
|
* - Facts, proposals, and PRD storage
|
|
15
15
|
* - Semantic similarity search
|
|
16
16
|
*
|
|
@@ -54,10 +54,8 @@ const DEFAULTS = {
|
|
|
54
54
|
// Configuration
|
|
55
55
|
// ============================================================
|
|
56
56
|
|
|
57
|
-
const { getProjectRoot } = require('./flow-paths');
|
|
58
|
-
const
|
|
59
|
-
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
60
|
-
const MEMORY_DIR = path.join(WORKFLOW_DIR, 'memory');
|
|
57
|
+
const { getProjectRoot, PATHS } = require('./flow-paths');
|
|
58
|
+
const MEMORY_DIR = path.join(PATHS.workflow, 'memory');
|
|
61
59
|
const DB_PATH = path.join(MEMORY_DIR, 'local.db');
|
|
62
60
|
|
|
63
61
|
// ============================================================
|
|
@@ -424,21 +422,21 @@ let embeddingsAvailable = null; // null = unknown, true/false after first check
|
|
|
424
422
|
|
|
425
423
|
/**
|
|
426
424
|
* Get embedder (lazy load)
|
|
427
|
-
* Returns null if @
|
|
425
|
+
* Returns null if @huggingface/transformers is not installed
|
|
428
426
|
*/
|
|
429
427
|
async function getEmbedder() {
|
|
430
428
|
if (embeddingsAvailable === false) return null;
|
|
431
429
|
|
|
432
430
|
if (!embedder) {
|
|
433
431
|
try {
|
|
434
|
-
const { pipeline } = await import('@
|
|
432
|
+
const { pipeline } = await import('@huggingface/transformers');
|
|
435
433
|
embedder = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
|
|
436
434
|
embeddingsAvailable = true;
|
|
437
435
|
} catch (err) {
|
|
438
436
|
if (err.code === 'ERR_MODULE_NOT_FOUND' || err.code === 'MODULE_NOT_FOUND') {
|
|
439
437
|
embeddingsAvailable = false;
|
|
440
438
|
if (process.env.DEBUG) {
|
|
441
|
-
console.warn('[DEBUG] @
|
|
439
|
+
console.warn('[DEBUG] @huggingface/transformers not installed - semantic search disabled');
|
|
442
440
|
}
|
|
443
441
|
return null;
|
|
444
442
|
}
|
|
@@ -28,6 +28,7 @@ let _syncDecisionsToRules = null;
|
|
|
28
28
|
function syncDecisionsToRules() {
|
|
29
29
|
if (!_syncDecisionsToRules) {
|
|
30
30
|
_syncDecisionsToRules = require('./flow-rules-sync').syncDecisionsToRules;
|
|
31
|
+
const { PATHS } = require('./flow-utils');
|
|
31
32
|
}
|
|
32
33
|
return _syncDecisionsToRules();
|
|
33
34
|
}
|
|
@@ -36,7 +37,7 @@ function syncDecisionsToRules() {
|
|
|
36
37
|
// Configuration
|
|
37
38
|
// ============================================================
|
|
38
39
|
|
|
39
|
-
const DECISIONS_PATH =
|
|
40
|
+
const DECISIONS_PATH = PATHS.decisions;
|
|
40
41
|
|
|
41
42
|
// loadConfig() removed — getConfig() already handles errors gracefully
|
|
42
43
|
|
|
@@ -249,12 +250,15 @@ async function promoteFact(factId, dryRun = false) {
|
|
|
249
250
|
return true;
|
|
250
251
|
}
|
|
251
252
|
|
|
252
|
-
// Update decisions.md
|
|
253
|
+
// Update decisions.md through orchestrator
|
|
253
254
|
const newContent = appendToDecisions(formatted, decisionsContent);
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
255
|
+
try {
|
|
256
|
+
const { writeToDecisions } = require('./flow-learning-orchestrator');
|
|
257
|
+
await writeToDecisions({ content: newContent, entryText: fact.fact, caller: 'flow-memory-sync/promote', syncRules: true });
|
|
258
|
+
} catch (_err) {
|
|
259
|
+
fs.writeFileSync(DECISIONS_PATH, newContent);
|
|
260
|
+
syncDecisionsToRules();
|
|
261
|
+
}
|
|
258
262
|
|
|
259
263
|
// Mark fact as promoted
|
|
260
264
|
await memoryDb.markFactPromoted(factId, 'decisions.md');
|
|
@@ -324,15 +328,18 @@ async function autoPromote(config) {
|
|
|
324
328
|
}
|
|
325
329
|
|
|
326
330
|
if (promoted > 0) {
|
|
327
|
-
// Write decisions.md
|
|
328
|
-
|
|
329
|
-
|
|
331
|
+
// Write decisions.md through orchestrator, then mark as promoted in DB
|
|
332
|
+
try {
|
|
333
|
+
const { writeToDecisions } = require('./flow-learning-orchestrator');
|
|
334
|
+
await writeToDecisions({ content: currentContent, caller: 'flow-memory-sync/autoPromote', skipDedup: true, syncRules: true });
|
|
335
|
+
} catch (_err) {
|
|
336
|
+
fs.writeFileSync(DECISIONS_PATH, currentContent);
|
|
337
|
+
syncDecisionsToRules();
|
|
338
|
+
}
|
|
330
339
|
// Now safe to mark as promoted in DB
|
|
331
340
|
for (const id of promotedIds) {
|
|
332
341
|
await memoryDb.markFactPromoted(id, 'decisions.md');
|
|
333
342
|
}
|
|
334
|
-
// Sync to .claude/rules/ for Claude Code integration
|
|
335
|
-
syncDecisionsToRules();
|
|
336
343
|
await memoryDb.recordMemoryMetric('auto_promote');
|
|
337
344
|
}
|
|
338
345
|
|
package/scripts/flow-metrics.js
CHANGED
|
@@ -21,8 +21,7 @@ const path = require('node:path');
|
|
|
21
21
|
const { getProjectRoot, getConfig, PATHS, colors, showHelp: showHelpGeneric, readJson } = require('./flow-utils');
|
|
22
22
|
const { success, error: errorMsg } = require('./flow-output');
|
|
23
23
|
|
|
24
|
-
const
|
|
25
|
-
const METRICS_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'command-metrics.json');
|
|
24
|
+
const METRICS_PATH = PATHS.commandMetrics;
|
|
26
25
|
|
|
27
26
|
// ============================================================
|
|
28
27
|
// Metrics Data Structure
|
|
@@ -29,9 +29,8 @@ const fs = require('node:fs');
|
|
|
29
29
|
const path = require('node:path');
|
|
30
30
|
const { getProjectRoot, getConfig, PATHS, colors, readJson } = require('./flow-utils');
|
|
31
31
|
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
const MODEL_STATS_PATH = path.join(PROJECT_ROOT, '.workflow', 'state', 'model-stats.json');
|
|
32
|
+
const ADAPTERS_DIR = PATHS.modelAdapters;
|
|
33
|
+
const MODEL_STATS_PATH = PATHS.modelStatsLegacy;
|
|
35
34
|
|
|
36
35
|
// ============================================================
|
|
37
36
|
// Model Detection
|
|
@@ -31,13 +31,11 @@
|
|
|
31
31
|
|
|
32
32
|
const fs = require('node:fs');
|
|
33
33
|
const path = require('node:path');
|
|
34
|
-
const { getProjectRoot, safeJsonParse, colors: c, error, success } = require('./flow-utils');
|
|
34
|
+
const { getProjectRoot, safeJsonParse, safeJsonParseString, colors: c, error, success, PATHS } = require('./flow-utils');
|
|
35
35
|
|
|
36
|
-
const
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
const ENV_PATH = path.join(PROJECT_ROOT, '.env');
|
|
40
|
-
const SESSION_STATE_PATH = path.join(WORKFLOW_DIR, 'state', 'session-state.json');
|
|
36
|
+
const CONFIG_PATH = path.join(PATHS.workflow, 'config.json');
|
|
37
|
+
const ENV_PATH = path.join(PATHS.root, '.env');
|
|
38
|
+
const SESSION_STATE_PATH = path.join(PATHS.workflow, 'state', 'session-state.json');
|
|
41
39
|
|
|
42
40
|
/**
|
|
43
41
|
* Known provider configurations
|
|
@@ -106,7 +104,7 @@ function readConfig() {
|
|
|
106
104
|
* @param {Object} config - Config to write
|
|
107
105
|
*/
|
|
108
106
|
function writeConfig(config) {
|
|
109
|
-
fs.mkdirSync(
|
|
107
|
+
fs.mkdirSync(PATHS.workflow, { recursive: true });
|
|
110
108
|
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
111
109
|
}
|
|
112
110
|
|
|
@@ -374,8 +372,12 @@ async function testLocalProvider(endpoint) {
|
|
|
374
372
|
res.on('data', chunk => data += chunk);
|
|
375
373
|
res.on('end', () => {
|
|
376
374
|
try {
|
|
377
|
-
const parsed =
|
|
378
|
-
|
|
375
|
+
const parsed = safeJsonParseString(data, null);
|
|
376
|
+
if (!parsed) {
|
|
377
|
+
resolve({ success: false, message: 'Invalid JSON response from Ollama' });
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
const models = parsed.models?.map(m => m.name) ?? [];
|
|
379
381
|
resolve({
|
|
380
382
|
success: true,
|
|
381
383
|
message: `Connected to Ollama. Found ${models.length} models.`,
|
|
@@ -405,115 +407,81 @@ async function testLocalProvider(endpoint) {
|
|
|
405
407
|
* Test LM Studio provider
|
|
406
408
|
*/
|
|
407
409
|
async function testLMStudio(baseEndpoint) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
return new Promise((resolve) => {
|
|
410
|
+
try {
|
|
411
411
|
// LM Studio uses OpenAI-compatible endpoint
|
|
412
412
|
const endpoint = baseEndpoint.replace(':11434', ':1234');
|
|
413
413
|
const url = new URL('/v1/models', endpoint);
|
|
414
414
|
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
});
|
|
428
|
-
} catch (err) {
|
|
429
|
-
resolve({ success: false, message: 'No local LLM detected' });
|
|
430
|
-
}
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
|
|
434
|
-
req.on('error', () => {
|
|
435
|
-
resolve({ success: false, message: 'No local LLM detected at localhost:11434 or :1234' });
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
req.end();
|
|
439
|
-
});
|
|
415
|
+
const res = await fetch(url, { method: 'GET', signal: AbortSignal.timeout(5000) });
|
|
416
|
+
const parsed = await res.json();
|
|
417
|
+
const models = parsed.data?.map(m => m.id) || [];
|
|
418
|
+
return {
|
|
419
|
+
success: true,
|
|
420
|
+
message: `Connected to LM Studio. Found ${models.length} models.`,
|
|
421
|
+
models,
|
|
422
|
+
provider: 'lmstudio'
|
|
423
|
+
};
|
|
424
|
+
} catch (_err) {
|
|
425
|
+
return { success: false, message: 'No local LLM detected at localhost:11434 or :1234' };
|
|
426
|
+
}
|
|
440
427
|
}
|
|
441
428
|
|
|
442
429
|
/**
|
|
443
430
|
* Test cloud provider connection
|
|
444
431
|
*/
|
|
445
432
|
async function testCloudProvider(providerName, endpoint, apiKey) {
|
|
446
|
-
|
|
433
|
+
let url, headers;
|
|
447
434
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
return;
|
|
464
|
-
default:
|
|
465
|
-
reject(new Error(`Unknown cloud provider: ${providerName}`));
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
435
|
+
switch (providerName) {
|
|
436
|
+
case 'openai':
|
|
437
|
+
url = new URL('/v1/models', endpoint);
|
|
438
|
+
headers = { 'Authorization': `Bearer ${apiKey}` };
|
|
439
|
+
break;
|
|
440
|
+
case 'google':
|
|
441
|
+
url = new URL('/v1beta/models', endpoint);
|
|
442
|
+
headers = { 'x-goog-api-key': apiKey };
|
|
443
|
+
break;
|
|
444
|
+
case 'anthropic':
|
|
445
|
+
// Anthropic doesn't have a models list endpoint, just test with a simple check
|
|
446
|
+
return { success: true, message: 'API key format valid (Anthropic)' };
|
|
447
|
+
default:
|
|
448
|
+
throw new Error(`Unknown cloud provider: ${providerName}`);
|
|
449
|
+
}
|
|
468
450
|
|
|
469
|
-
|
|
470
|
-
let data = '';
|
|
471
|
-
res.on('data', chunk => data += chunk);
|
|
472
|
-
res.on('end', () => {
|
|
473
|
-
if (res.statusCode === 200) {
|
|
474
|
-
try {
|
|
475
|
-
const parsed = JSON.parse(data);
|
|
476
|
-
|
|
477
|
-
// Check for prototype pollution in API response
|
|
478
|
-
if (hasDangerousKeys(parsed)) {
|
|
479
|
-
resolve({ success: false, message: 'Invalid API response (security check failed)' });
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
let models = [];
|
|
484
|
-
|
|
485
|
-
if (providerName === 'openai') {
|
|
486
|
-
models = parsed.data?.map(m => m.id).filter(id =>
|
|
487
|
-
id.startsWith('gpt-4') || id.startsWith('o1')
|
|
488
|
-
).slice(0, 10) || [];
|
|
489
|
-
} else if (providerName === 'google') {
|
|
490
|
-
models = parsed.models?.map(m => m.name.replace('models/', '')) || [];
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
resolve({
|
|
494
|
-
success: true,
|
|
495
|
-
message: `Connected to ${providerName}. Found ${models.length} models.`,
|
|
496
|
-
models
|
|
497
|
-
});
|
|
498
|
-
} catch (err) {
|
|
499
|
-
resolve({ success: true, message: `Connected to ${providerName}` });
|
|
500
|
-
}
|
|
501
|
-
} else if (res.statusCode === 401) {
|
|
502
|
-
resolve({ success: false, message: 'Invalid API key' });
|
|
503
|
-
} else {
|
|
504
|
-
resolve({ success: false, message: `API error: ${res.statusCode}` });
|
|
505
|
-
}
|
|
506
|
-
});
|
|
507
|
-
});
|
|
451
|
+
const res = await fetch(url, { method: 'GET', headers, signal: AbortSignal.timeout(10000) });
|
|
508
452
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
reject(new Error('Connection timeout'));
|
|
513
|
-
});
|
|
453
|
+
if (res.status === 200) {
|
|
454
|
+
try {
|
|
455
|
+
const parsed = await res.json();
|
|
514
456
|
|
|
515
|
-
|
|
516
|
-
|
|
457
|
+
// Check for prototype pollution in API response
|
|
458
|
+
if (hasDangerousKeys(parsed)) {
|
|
459
|
+
return { success: false, message: 'Invalid API response (security check failed)' };
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
let models = [];
|
|
463
|
+
|
|
464
|
+
if (providerName === 'openai') {
|
|
465
|
+
models = parsed.data?.map(m => m.id).filter(id =>
|
|
466
|
+
id.startsWith('gpt-4') || id.startsWith('o1')
|
|
467
|
+
).slice(0, 10) || [];
|
|
468
|
+
} else if (providerName === 'google') {
|
|
469
|
+
models = parsed.models?.map(m => m.name.replace('models/', '')) || [];
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return {
|
|
473
|
+
success: true,
|
|
474
|
+
message: `Connected to ${providerName}. Found ${models.length} models.`,
|
|
475
|
+
models
|
|
476
|
+
};
|
|
477
|
+
} catch (_err) {
|
|
478
|
+
return { success: true, message: `Connected to ${providerName}` };
|
|
479
|
+
}
|
|
480
|
+
} else if (res.status === 401) {
|
|
481
|
+
return { success: false, message: 'Invalid API key' };
|
|
482
|
+
} else {
|
|
483
|
+
return { success: false, message: `API error: ${res.status}` };
|
|
484
|
+
}
|
|
517
485
|
}
|
|
518
486
|
|
|
519
487
|
/**
|
|
@@ -29,7 +29,7 @@ const {
|
|
|
29
29
|
getConfig,
|
|
30
30
|
printHeader,
|
|
31
31
|
printSection,
|
|
32
|
-
estimateTokens
|
|
32
|
+
estimateTokens, PATHS
|
|
33
33
|
} = require('./flow-utils');
|
|
34
34
|
|
|
35
35
|
const { analyzeTask } = require('./flow-task-analyzer');
|
|
@@ -61,7 +61,7 @@ try {
|
|
|
61
61
|
// Constants
|
|
62
62
|
// ============================================================
|
|
63
63
|
|
|
64
|
-
const CONFIG_PATH = path.join(
|
|
64
|
+
const CONFIG_PATH = path.join(PATHS.workflow, 'config.json');
|
|
65
65
|
|
|
66
66
|
const ROUTING_STRATEGIES = {
|
|
67
67
|
'quality-first': 'Select highest-capability model matching requirements',
|
|
@@ -27,11 +27,10 @@
|
|
|
27
27
|
|
|
28
28
|
const fs = require('node:fs');
|
|
29
29
|
const path = require('node:path');
|
|
30
|
-
const { getProjectRoot, getConfig, PATHS, colors, writeJson, ensureDir, readJson } = require('./flow-utils');
|
|
30
|
+
const { getProjectRoot, getConfig, PATHS, colors, writeJson, ensureDir, readJson, safeJsonParse } = require('./flow-utils');
|
|
31
31
|
const { success, error: errorMsg } = require('./flow-output');
|
|
32
32
|
|
|
33
|
-
const
|
|
34
|
-
const APPROACHES_DIR = path.join(PROJECT_ROOT, '.workflow', 'state', 'approaches');
|
|
33
|
+
const APPROACHES_DIR = path.join(PATHS.state, 'approaches');
|
|
35
34
|
|
|
36
35
|
// ============================================================
|
|
37
36
|
// Configuration
|
|
@@ -351,9 +350,8 @@ function listSessions(limit = 10) {
|
|
|
351
350
|
return fs.readdirSync(APPROACHES_DIR)
|
|
352
351
|
.filter(f => f.endsWith('.json'))
|
|
353
352
|
.map(f => {
|
|
354
|
-
const session =
|
|
355
|
-
|
|
356
|
-
);
|
|
353
|
+
const session = safeJsonParse(path.join(APPROACHES_DIR, f), null);
|
|
354
|
+
if (!session) return null;
|
|
357
355
|
return {
|
|
358
356
|
id: session.id,
|
|
359
357
|
task: session.task?.description?.slice(0, 50) + '...',
|
|
@@ -362,6 +360,7 @@ function listSessions(limit = 10) {
|
|
|
362
360
|
createdAt: session.createdAt
|
|
363
361
|
};
|
|
364
362
|
})
|
|
363
|
+
.filter(Boolean)
|
|
365
364
|
.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
|
|
366
365
|
.slice(0, limit);
|
|
367
366
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
2
|
/**
|
|
5
3
|
* Project Context Generator - Extracted from flow-orchestrate.js
|
|
6
4
|
*
|
|
@@ -17,7 +15,7 @@
|
|
|
17
15
|
|
|
18
16
|
const fs = require('node:fs');
|
|
19
17
|
const path = require('node:path');
|
|
20
|
-
const { getProjectRoot, colors, getConfig } = require('./flow-utils');
|
|
18
|
+
const { getProjectRoot, colors, getConfig, PATHS } = require('./flow-utils');
|
|
21
19
|
const {
|
|
22
20
|
buildExportMap,
|
|
23
21
|
loadCachedExportMap,
|
|
@@ -26,17 +24,15 @@ const {
|
|
|
26
24
|
setProjectRoot: setExportScannerRoot
|
|
27
25
|
} = require('./flow-export-scanner');
|
|
28
26
|
|
|
29
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
30
|
-
|
|
31
27
|
// Set export scanner project root to match
|
|
32
|
-
setExportScannerRoot(
|
|
28
|
+
setExportScannerRoot(PATHS.root);
|
|
33
29
|
|
|
34
30
|
function log(color, ...args) {
|
|
35
31
|
console.log(colors[color] + args.join(' ') + colors.reset);
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
class ProjectContextGenerator {
|
|
39
|
-
constructor(projectRoot =
|
|
35
|
+
constructor(projectRoot = PATHS.root) {
|
|
40
36
|
this.projectRoot = projectRoot;
|
|
41
37
|
this.contextPath = path.join(projectRoot, '.workflow/state/hybrid-context.md');
|
|
42
38
|
this.cacheMaxAge = 60 * 60 * 1000; // 1 hour
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
2
|
/**
|
|
5
3
|
* Rollback Manager - Extracted from flow-orchestrate.js
|
|
6
4
|
*
|
|
@@ -10,12 +8,9 @@
|
|
|
10
8
|
|
|
11
9
|
const fs = require('node:fs');
|
|
12
10
|
const path = require('node:path');
|
|
13
|
-
const { getProjectRoot, colors } = require('./flow-utils');
|
|
11
|
+
const { getProjectRoot, colors, PATHS } = require('./flow-utils');
|
|
14
12
|
const { readJson } = require('./flow-io');
|
|
15
13
|
|
|
16
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
17
|
-
const STATE_DIR = path.join(PROJECT_ROOT, '.workflow', 'state');
|
|
18
|
-
|
|
19
14
|
function log(color, ...args) {
|
|
20
15
|
console.log(colors[color] + args.join(' ') + colors.reset);
|
|
21
16
|
}
|
|
@@ -24,7 +19,7 @@ class RollbackManager {
|
|
|
24
19
|
constructor() {
|
|
25
20
|
this.createdFiles = [];
|
|
26
21
|
this.modifiedFiles = [];
|
|
27
|
-
this.checkpointPath = path.join(
|
|
22
|
+
this.checkpointPath = path.join(PATHS.state, 'rollback-checkpoint.json');
|
|
28
23
|
}
|
|
29
24
|
|
|
30
25
|
trackCreation(filePath) {
|
|
@@ -68,7 +63,7 @@ class RollbackManager {
|
|
|
68
63
|
log('dim', ` 🗑️ Deleted: ${filePath}`);
|
|
69
64
|
|
|
70
65
|
let dir = path.dirname(filePath);
|
|
71
|
-
while (dir !==
|
|
66
|
+
while (dir !== PATHS.root && fs.existsSync(dir)) {
|
|
72
67
|
const files = fs.readdirSync(dir);
|
|
73
68
|
if (files.length === 0) {
|
|
74
69
|
fs.rmdirSync(dir);
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
2
|
/**
|
|
5
3
|
* State Manager - Extracted from flow-orchestrate.js
|
|
6
4
|
*
|
|
@@ -10,22 +8,18 @@
|
|
|
10
8
|
|
|
11
9
|
const fs = require('node:fs');
|
|
12
10
|
const path = require('node:path');
|
|
13
|
-
const { getProjectRoot, colors, getConfig, writeJson } = require('./flow-utils');
|
|
11
|
+
const { getProjectRoot, colors, getConfig, writeJson, PATHS } = require('./flow-utils');
|
|
14
12
|
const { readJson } = require('./flow-io');
|
|
15
13
|
const { loadCachedExportMap } = require('./flow-export-scanner');
|
|
16
14
|
const durableSession = require('./flow-durable-session');
|
|
17
15
|
|
|
18
|
-
const PROJECT_ROOT = getProjectRoot();
|
|
19
|
-
const WORKFLOW_DIR = path.join(PROJECT_ROOT, '.workflow');
|
|
20
|
-
const STATE_DIR = path.join(WORKFLOW_DIR, 'state');
|
|
21
|
-
|
|
22
16
|
function log(color, ...args) {
|
|
23
17
|
console.log(colors[color] + args.join(' ') + colors.reset);
|
|
24
18
|
}
|
|
25
19
|
|
|
26
20
|
class StateManager {
|
|
27
21
|
updateRequestLog(step, status, mode = 'hybrid', executor = '') {
|
|
28
|
-
const logPath =
|
|
22
|
+
const logPath = PATHS.requestLog;
|
|
29
23
|
const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 16);
|
|
30
24
|
|
|
31
25
|
const entry = `
|
|
@@ -49,7 +43,7 @@ ${step.description || ''}
|
|
|
49
43
|
updateAppMap(update) {
|
|
50
44
|
if (!update) return;
|
|
51
45
|
|
|
52
|
-
const mapPath =
|
|
46
|
+
const mapPath = PATHS.appMap;
|
|
53
47
|
if (!fs.existsSync(mapPath)) return;
|
|
54
48
|
|
|
55
49
|
let content = fs.readFileSync(mapPath, 'utf-8');
|
|
@@ -111,7 +105,7 @@ ${step.description || ''}
|
|
|
111
105
|
// DEPRECATED: This path is kept for backward compatibility but will be removed
|
|
112
106
|
// Enable durableSteps in config.json to use the modern session management
|
|
113
107
|
console.warn('[DEPRECATED] Using legacy hybrid-session.json - enable durableSteps.enabled in config.json');
|
|
114
|
-
const sessionPath = path.join(
|
|
108
|
+
const sessionPath = path.join(PATHS.state, 'hybrid-session.json');
|
|
115
109
|
|
|
116
110
|
let session = {
|
|
117
111
|
sessionId: `sess-${Date.now()}`,
|
|
@@ -150,7 +144,7 @@ ${step.description || ''}
|
|
|
150
144
|
}
|
|
151
145
|
|
|
152
146
|
// Legacy fallback - DEPRECATED
|
|
153
|
-
const sessionPath = path.join(
|
|
147
|
+
const sessionPath = path.join(PATHS.state, 'hybrid-session.json');
|
|
154
148
|
const legacySession = readJson(sessionPath, null);
|
|
155
149
|
if (legacySession) {
|
|
156
150
|
console.warn('[DEPRECATED] Reading legacy hybrid-session.json - enable durableSteps.enabled in config.json');
|
|
@@ -160,7 +154,7 @@ ${step.description || ''}
|
|
|
160
154
|
}
|
|
161
155
|
|
|
162
156
|
saveResults(results) {
|
|
163
|
-
const resultsPath = path.join(
|
|
157
|
+
const resultsPath = path.join(PATHS.state, 'hybrid-results.json');
|
|
164
158
|
fs.writeFileSync(resultsPath, JSON.stringify(results, null, 2));
|
|
165
159
|
}
|
|
166
160
|
|
|
@@ -192,7 +186,7 @@ ${step.description || ''}
|
|
|
192
186
|
};
|
|
193
187
|
|
|
194
188
|
// Try to load from config (primary source)
|
|
195
|
-
const configPath = path.join(
|
|
189
|
+
const configPath = path.join(PATHS.workflow, 'config.json');
|
|
196
190
|
const config = readJson(configPath, null);
|
|
197
191
|
if (config) {
|
|
198
192
|
const projectCtx = config.hybrid?.projectContext || {};
|
|
@@ -295,7 +289,7 @@ ${step.description || ''}
|
|
|
295
289
|
}
|
|
296
290
|
|
|
297
291
|
// Supplement with app-map.md if no exports found
|
|
298
|
-
const appMapPath =
|
|
292
|
+
const appMapPath = PATHS.appMap;
|
|
299
293
|
if (fs.existsSync(appMapPath) && !context.availableComponents) {
|
|
300
294
|
try {
|
|
301
295
|
const appMap = fs.readFileSync(appMapPath, 'utf-8');
|