agileflow 3.1.0 → 3.2.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/CHANGELOG.md +10 -0
- package/README.md +57 -85
- package/lib/dashboard-automations.js +130 -0
- package/lib/dashboard-git.js +254 -0
- package/lib/dashboard-inbox.js +64 -0
- package/lib/dashboard-protocol.js +1 -0
- package/lib/dashboard-server.js +114 -924
- package/lib/dashboard-session.js +136 -0
- package/lib/dashboard-status.js +72 -0
- package/lib/dashboard-terminal.js +354 -0
- package/lib/dashboard-websocket.js +88 -0
- package/lib/drivers/codex-driver.ts +4 -4
- package/lib/logger.js +106 -0
- package/package.json +4 -2
- package/scripts/agileflow-configure.js +2 -2
- package/scripts/agileflow-welcome.js +409 -434
- package/scripts/claude-tmux.sh +80 -2
- package/scripts/context-loader.js +4 -9
- package/scripts/lib/browser-qa-evidence.js +409 -0
- package/scripts/lib/browser-qa-status.js +192 -0
- package/scripts/lib/command-prereqs.js +280 -0
- package/scripts/lib/configure-detect.js +92 -2
- package/scripts/lib/configure-features.js +295 -1
- package/scripts/lib/context-formatter.js +468 -233
- package/scripts/lib/context-loader.js +27 -15
- package/scripts/lib/damage-control-utils.js +8 -1
- package/scripts/lib/feature-catalog.js +321 -0
- package/scripts/lib/portable-tasks-cli.js +274 -0
- package/scripts/lib/portable-tasks.js +479 -0
- package/scripts/lib/signal-detectors.js +1 -1
- package/scripts/lib/team-events.js +86 -1
- package/scripts/obtain-context.js +28 -4
- package/scripts/smart-detect.js +17 -0
- package/scripts/strip-ai-attribution.js +63 -0
- package/scripts/team-manager.js +7 -2
- package/scripts/welcome-deferred.js +437 -0
- package/src/core/agents/browser-qa.md +328 -0
- package/src/core/agents/perf-analyzer-assets.md +174 -0
- package/src/core/agents/perf-analyzer-bundle.md +165 -0
- package/src/core/agents/perf-analyzer-caching.md +160 -0
- package/src/core/agents/perf-analyzer-compute.md +165 -0
- package/src/core/agents/perf-analyzer-memory.md +182 -0
- package/src/core/agents/perf-analyzer-network.md +157 -0
- package/src/core/agents/perf-analyzer-queries.md +155 -0
- package/src/core/agents/perf-analyzer-rendering.md +156 -0
- package/src/core/agents/perf-consensus.md +280 -0
- package/src/core/agents/security-analyzer-api.md +199 -0
- package/src/core/agents/security-analyzer-auth.md +160 -0
- package/src/core/agents/security-analyzer-authz.md +168 -0
- package/src/core/agents/security-analyzer-deps.md +147 -0
- package/src/core/agents/security-analyzer-infra.md +176 -0
- package/src/core/agents/security-analyzer-injection.md +148 -0
- package/src/core/agents/security-analyzer-input.md +191 -0
- package/src/core/agents/security-analyzer-secrets.md +175 -0
- package/src/core/agents/security-consensus.md +276 -0
- package/src/core/agents/test-analyzer-assertions.md +181 -0
- package/src/core/agents/test-analyzer-coverage.md +183 -0
- package/src/core/agents/test-analyzer-fragility.md +185 -0
- package/src/core/agents/test-analyzer-integration.md +155 -0
- package/src/core/agents/test-analyzer-maintenance.md +173 -0
- package/src/core/agents/test-analyzer-mocking.md +178 -0
- package/src/core/agents/test-analyzer-patterns.md +189 -0
- package/src/core/agents/test-analyzer-structure.md +177 -0
- package/src/core/agents/test-consensus.md +294 -0
- package/src/core/commands/{legal/audit.md → audit/legal.md} +13 -13
- package/src/core/commands/{logic/audit.md → audit/logic.md} +12 -12
- package/src/core/commands/audit/performance.md +443 -0
- package/src/core/commands/audit/security.md +443 -0
- package/src/core/commands/audit/test.md +442 -0
- package/src/core/commands/babysit.md +505 -463
- package/src/core/commands/browser-qa.md +240 -0
- package/src/core/commands/configure.md +8 -8
- package/src/core/commands/research/ask.md +42 -9
- package/src/core/commands/research/import.md +14 -8
- package/src/core/commands/research/list.md +17 -16
- package/src/core/commands/research/synthesize.md +8 -8
- package/src/core/commands/research/view.md +28 -4
- package/src/core/commands/whats-new.md +2 -2
- package/src/core/experts/devops/expertise.yaml +13 -2
- package/src/core/experts/documentation/expertise.yaml +26 -4
- package/src/core/profiles/COMPARISON.md +170 -0
- package/src/core/profiles/README.md +178 -0
- package/src/core/profiles/claude-code.yaml +111 -0
- package/src/core/profiles/codex.yaml +103 -0
- package/src/core/profiles/cursor.yaml +134 -0
- package/src/core/profiles/examples.js +250 -0
- package/src/core/profiles/loader.js +235 -0
- package/src/core/profiles/windsurf.yaml +159 -0
- package/src/core/teams/logic-audit.json +6 -0
- package/src/core/teams/perf-audit.json +71 -0
- package/src/core/teams/security-audit.json +71 -0
- package/src/core/teams/test-audit.json +71 -0
- package/src/core/templates/browser-qa-spec.yaml +94 -0
- package/src/core/templates/command-prerequisites.yaml +169 -0
- package/src/core/templates/damage-control-patterns.yaml +9 -0
- package/tools/cli/installers/ide/_base-ide.js +33 -3
- package/tools/cli/installers/ide/claude-code.js +2 -69
- package/tools/cli/installers/ide/codex.js +9 -9
- package/tools/cli/installers/ide/cursor.js +165 -4
- package/tools/cli/installers/ide/windsurf.js +237 -6
- package/tools/cli/lib/content-transformer.js +234 -9
- package/tools/cli/lib/docs-setup.js +1 -1
- package/tools/cli/lib/ide-generator.js +357 -0
- package/tools/cli/lib/ide-registry.js +2 -2
- package/scripts/tmux-task-name.sh +0 -105
- package/scripts/tmux-task-watcher.sh +0 -344
|
@@ -62,6 +62,20 @@ const FEATURES = {
|
|
|
62
62
|
metadataOnly: false,
|
|
63
63
|
description: 'Enable Claude Code native Agent Teams (sets env var in .claude/settings.json)',
|
|
64
64
|
},
|
|
65
|
+
noaiattribution: {
|
|
66
|
+
preToolUseHook: true,
|
|
67
|
+
script: 'strip-ai-attribution.js',
|
|
68
|
+
description: 'Block git commits containing AI attribution (Co-Authored-By, etc.)',
|
|
69
|
+
},
|
|
70
|
+
browserqa: {
|
|
71
|
+
metadataOnly: false,
|
|
72
|
+
description:
|
|
73
|
+
'Agentic browser testing with Playwright (Bowser four-layer pattern). Screenshot evidence, 80% pass rate threshold.',
|
|
74
|
+
},
|
|
75
|
+
contextverbosity: {
|
|
76
|
+
metadataOnly: true,
|
|
77
|
+
description: 'Control how much context is loaded per command (full/lite/minimal)',
|
|
78
|
+
},
|
|
65
79
|
};
|
|
66
80
|
|
|
67
81
|
const PROFILES = {
|
|
@@ -76,14 +90,23 @@ const PROFILES = {
|
|
|
76
90
|
'selfimprove',
|
|
77
91
|
'askuserquestion',
|
|
78
92
|
'tmuxautospawn',
|
|
93
|
+
'noaiattribution',
|
|
79
94
|
],
|
|
80
95
|
archivalDays: 30,
|
|
81
96
|
},
|
|
82
97
|
basic: {
|
|
83
98
|
description: 'Essential hooks + archival (SessionStart + PreCompact + Archival)',
|
|
84
|
-
enable: [
|
|
99
|
+
enable: [
|
|
100
|
+
'sessionstart',
|
|
101
|
+
'precompact',
|
|
102
|
+
'archival',
|
|
103
|
+
'askuserquestion',
|
|
104
|
+
'tmuxautospawn',
|
|
105
|
+
'noaiattribution',
|
|
106
|
+
],
|
|
85
107
|
disable: ['statusline', 'ralphloop', 'selfimprove'],
|
|
86
108
|
archivalDays: 30,
|
|
109
|
+
contextVerbosity: 'lite',
|
|
87
110
|
},
|
|
88
111
|
minimal: {
|
|
89
112
|
description: 'SessionStart + archival only',
|
|
@@ -97,6 +120,7 @@ const PROFILES = {
|
|
|
97
120
|
'tmuxautospawn',
|
|
98
121
|
],
|
|
99
122
|
archivalDays: 30,
|
|
123
|
+
contextVerbosity: 'lite',
|
|
100
124
|
},
|
|
101
125
|
none: {
|
|
102
126
|
description: 'Disable all AgileFlow features',
|
|
@@ -109,6 +133,7 @@ const PROFILES = {
|
|
|
109
133
|
'selfimprove',
|
|
110
134
|
'askuserquestion',
|
|
111
135
|
'tmuxautospawn',
|
|
136
|
+
'noaiattribution',
|
|
112
137
|
],
|
|
113
138
|
},
|
|
114
139
|
experimental: {
|
|
@@ -123,6 +148,7 @@ const PROFILES = {
|
|
|
123
148
|
'selfimprove',
|
|
124
149
|
'askuserquestion',
|
|
125
150
|
'tmuxautospawn',
|
|
151
|
+
'noaiattribution',
|
|
126
152
|
],
|
|
127
153
|
archivalDays: 30,
|
|
128
154
|
experimental: {
|
|
@@ -454,6 +480,48 @@ function enableFeature(feature, options = {}, version) {
|
|
|
454
480
|
return enableDamageControl(settings, options, version);
|
|
455
481
|
}
|
|
456
482
|
|
|
483
|
+
// Handle no AI attribution
|
|
484
|
+
if (feature === 'noaiattribution') {
|
|
485
|
+
return enableNoAiAttribution(settings, version);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Handle browser QA (agentic browser testing)
|
|
489
|
+
if (feature === 'browserqa') {
|
|
490
|
+
return enableBrowserQa(version);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Handle context verbosity (metadata only)
|
|
494
|
+
if (feature === 'contextverbosity') {
|
|
495
|
+
const mode = options.mode || 'lite';
|
|
496
|
+
const validModes = ['full', 'lite', 'minimal'];
|
|
497
|
+
if (!validModes.includes(mode)) {
|
|
498
|
+
error(`Invalid verbosity mode: ${mode}. Valid: ${validModes.join(', ')}`);
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
updateMetadata(
|
|
502
|
+
{
|
|
503
|
+
features: {
|
|
504
|
+
contextVerbosity: {
|
|
505
|
+
enabled: true,
|
|
506
|
+
mode,
|
|
507
|
+
version,
|
|
508
|
+
at: new Date().toISOString(),
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
version
|
|
513
|
+
);
|
|
514
|
+
success(`Context verbosity set to: ${mode}`);
|
|
515
|
+
if (mode === 'lite') {
|
|
516
|
+
info('Lite: summary table + git status + active stories + smart recommendations');
|
|
517
|
+
info('Skips: full file dumps, feature catalog, research content, ideation');
|
|
518
|
+
} else if (mode === 'minimal') {
|
|
519
|
+
info('Minimal: summary table only with story counts');
|
|
520
|
+
info('Skips: everything except compact summary');
|
|
521
|
+
}
|
|
522
|
+
return true;
|
|
523
|
+
}
|
|
524
|
+
|
|
457
525
|
const featureConfig = FEATURES[feature];
|
|
458
526
|
const contentHash = featureConfig?.script
|
|
459
527
|
? hashFile(path.join(SCRIPTS_DIR, featureConfig.script))
|
|
@@ -656,6 +724,70 @@ function enableDamageControl(settings, options, version) {
|
|
|
656
724
|
return true;
|
|
657
725
|
}
|
|
658
726
|
|
|
727
|
+
/**
|
|
728
|
+
* Enable no AI attribution feature
|
|
729
|
+
*/
|
|
730
|
+
function enableNoAiAttribution(settings, version) {
|
|
731
|
+
const scriptName = 'strip-ai-attribution.js';
|
|
732
|
+
|
|
733
|
+
if (!scriptExists(scriptName)) {
|
|
734
|
+
error(`Script not found: ${getScriptPath(scriptName)}`);
|
|
735
|
+
info('Run "npx agileflow update" to reinstall scripts');
|
|
736
|
+
return false;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// Initialize PreToolUse array
|
|
740
|
+
if (!settings.hooks.PreToolUse) {
|
|
741
|
+
settings.hooks.PreToolUse = [];
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
const scriptFullPath = path.join(process.cwd(), '.agileflow', 'scripts', scriptName);
|
|
745
|
+
|
|
746
|
+
// Remove existing hook if any
|
|
747
|
+
for (const entry of settings.hooks.PreToolUse) {
|
|
748
|
+
if (entry.matcher === 'Bash' && Array.isArray(entry.hooks)) {
|
|
749
|
+
entry.hooks = entry.hooks.filter(h => !h.command?.includes('strip-ai-attribution'));
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
// Clean up empty entries
|
|
753
|
+
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(
|
|
754
|
+
h => Array.isArray(h.hooks) && h.hooks.length > 0
|
|
755
|
+
);
|
|
756
|
+
|
|
757
|
+
// Add to existing Bash matcher or create new one
|
|
758
|
+
const bashEntry = settings.hooks.PreToolUse.find(h => h.matcher === 'Bash');
|
|
759
|
+
if (bashEntry) {
|
|
760
|
+
bashEntry.hooks.push({ type: 'command', command: `node ${scriptFullPath}`, timeout: 5 });
|
|
761
|
+
} else {
|
|
762
|
+
settings.hooks.PreToolUse.push({
|
|
763
|
+
matcher: 'Bash',
|
|
764
|
+
hooks: [{ type: 'command', command: `node ${scriptFullPath}`, timeout: 5 }],
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
const contentHash = hashFile(path.join(SCRIPTS_DIR, scriptName));
|
|
769
|
+
updateMetadata(
|
|
770
|
+
{
|
|
771
|
+
features: {
|
|
772
|
+
noaiattribution: {
|
|
773
|
+
enabled: true,
|
|
774
|
+
version,
|
|
775
|
+
...(contentHash ? { contentHash } : {}),
|
|
776
|
+
at: new Date().toISOString(),
|
|
777
|
+
},
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
version
|
|
781
|
+
);
|
|
782
|
+
|
|
783
|
+
writeJSON('.claude/settings.json', settings);
|
|
784
|
+
updateGitignore();
|
|
785
|
+
|
|
786
|
+
success('AI attribution blocking enabled');
|
|
787
|
+
info('Git commits with AI footers (Co-Authored-By, etc.) will be blocked');
|
|
788
|
+
return true;
|
|
789
|
+
}
|
|
790
|
+
|
|
659
791
|
// ============================================================================
|
|
660
792
|
// DISABLE FEATURE
|
|
661
793
|
// ============================================================================
|
|
@@ -925,6 +1057,79 @@ function disableFeature(feature, version) {
|
|
|
925
1057
|
return true;
|
|
926
1058
|
}
|
|
927
1059
|
|
|
1060
|
+
// Disable browser QA
|
|
1061
|
+
if (feature === 'browserqa') {
|
|
1062
|
+
updateMetadata(
|
|
1063
|
+
{
|
|
1064
|
+
features: {
|
|
1065
|
+
browserqa: {
|
|
1066
|
+
enabled: false,
|
|
1067
|
+
version,
|
|
1068
|
+
at: new Date().toISOString(),
|
|
1069
|
+
},
|
|
1070
|
+
},
|
|
1071
|
+
},
|
|
1072
|
+
version
|
|
1073
|
+
);
|
|
1074
|
+
success('Browser QA disabled');
|
|
1075
|
+
info('Agentic browser testing deactivated');
|
|
1076
|
+
return true;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
// Disable context verbosity (reset to full)
|
|
1080
|
+
if (feature === 'contextverbosity') {
|
|
1081
|
+
updateMetadata(
|
|
1082
|
+
{
|
|
1083
|
+
features: {
|
|
1084
|
+
contextVerbosity: {
|
|
1085
|
+
enabled: false,
|
|
1086
|
+
mode: 'full',
|
|
1087
|
+
version,
|
|
1088
|
+
at: new Date().toISOString(),
|
|
1089
|
+
},
|
|
1090
|
+
},
|
|
1091
|
+
},
|
|
1092
|
+
version
|
|
1093
|
+
);
|
|
1094
|
+
success('Context verbosity reset to full');
|
|
1095
|
+
return true;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
// Disable no AI attribution
|
|
1099
|
+
if (feature === 'noaiattribution') {
|
|
1100
|
+
if (settings.hooks?.PreToolUse && Array.isArray(settings.hooks.PreToolUse)) {
|
|
1101
|
+
for (const entry of settings.hooks.PreToolUse) {
|
|
1102
|
+
if (entry.matcher === 'Bash' && Array.isArray(entry.hooks)) {
|
|
1103
|
+
entry.hooks = entry.hooks.filter(h => !h.command?.includes('strip-ai-attribution'));
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
// Clean up empty entries
|
|
1107
|
+
settings.hooks.PreToolUse = settings.hooks.PreToolUse.filter(
|
|
1108
|
+
h => Array.isArray(h.hooks) && h.hooks.length > 0
|
|
1109
|
+
);
|
|
1110
|
+
if (settings.hooks.PreToolUse.length === 0) {
|
|
1111
|
+
delete settings.hooks.PreToolUse;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
updateMetadata(
|
|
1116
|
+
{
|
|
1117
|
+
features: {
|
|
1118
|
+
noaiattribution: {
|
|
1119
|
+
enabled: false,
|
|
1120
|
+
version,
|
|
1121
|
+
at: new Date().toISOString(),
|
|
1122
|
+
},
|
|
1123
|
+
},
|
|
1124
|
+
},
|
|
1125
|
+
version
|
|
1126
|
+
);
|
|
1127
|
+
|
|
1128
|
+
writeJSON('.claude/settings.json', settings);
|
|
1129
|
+
success('AI attribution blocking disabled');
|
|
1130
|
+
return true;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
928
1133
|
writeJSON('.claude/settings.json', settings);
|
|
929
1134
|
updateMetadata(
|
|
930
1135
|
{ features: { [feature]: { enabled: false, version, at: new Date().toISOString() } } },
|
|
@@ -966,6 +1171,11 @@ function applyProfile(profileName, options = {}, version) {
|
|
|
966
1171
|
profile.disable.forEach(f => disableFeature(f, version));
|
|
967
1172
|
}
|
|
968
1173
|
|
|
1174
|
+
// Apply context verbosity if specified in profile
|
|
1175
|
+
if (profile.contextVerbosity) {
|
|
1176
|
+
enableFeature('contextverbosity', { mode: profile.contextVerbosity }, version);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
969
1179
|
// Handle experimental profile settings
|
|
970
1180
|
if (profile.experimental) {
|
|
971
1181
|
updateMetadata(
|
|
@@ -1481,6 +1691,90 @@ function disableShellAliases() {
|
|
|
1481
1691
|
// CLAUDE.MD REINFORCEMENT
|
|
1482
1692
|
// ============================================================================
|
|
1483
1693
|
|
|
1694
|
+
// ============================================================================
|
|
1695
|
+
// BROWSER QA
|
|
1696
|
+
// ============================================================================
|
|
1697
|
+
|
|
1698
|
+
/**
|
|
1699
|
+
* Enable browser QA (agentic browser testing)
|
|
1700
|
+
* Creates evidence directory structure, deploys spec template, updates metadata
|
|
1701
|
+
*/
|
|
1702
|
+
function enableBrowserQa(version) {
|
|
1703
|
+
// Create evidence directory structure + screenshots dir for visual verification
|
|
1704
|
+
const dirs = [
|
|
1705
|
+
'.agileflow/ui-review',
|
|
1706
|
+
'.agileflow/ui-review/runs',
|
|
1707
|
+
'.agileflow/ui-review/specs',
|
|
1708
|
+
'.agileflow/ui-review/baselines',
|
|
1709
|
+
'screenshots',
|
|
1710
|
+
];
|
|
1711
|
+
for (const dir of dirs) {
|
|
1712
|
+
ensureDir(dir);
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
// Deploy spec template if not exists
|
|
1716
|
+
const templateDest = path.join(
|
|
1717
|
+
process.cwd(),
|
|
1718
|
+
'.agileflow',
|
|
1719
|
+
'ui-review',
|
|
1720
|
+
'specs',
|
|
1721
|
+
'_template.yaml'
|
|
1722
|
+
);
|
|
1723
|
+
if (!fs.existsSync(templateDest)) {
|
|
1724
|
+
const templateSrc = path.join(process.cwd(), '.agileflow', 'templates', 'browser-qa-spec.yaml');
|
|
1725
|
+
if (fs.existsSync(templateSrc)) {
|
|
1726
|
+
fs.copyFileSync(templateSrc, templateDest);
|
|
1727
|
+
success('Deployed browser-qa spec template');
|
|
1728
|
+
} else {
|
|
1729
|
+
info('No spec template found - create YAML specs manually in .agileflow/ui-review/specs/');
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
// Check for Playwright
|
|
1734
|
+
let playwrightAvailable = false;
|
|
1735
|
+
try {
|
|
1736
|
+
require.resolve('playwright');
|
|
1737
|
+
playwrightAvailable = true;
|
|
1738
|
+
} catch {
|
|
1739
|
+
// Not installed
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
if (!playwrightAvailable) {
|
|
1743
|
+
warn('Playwright not found - install for browser automation:');
|
|
1744
|
+
info(' npm install --save-optional playwright');
|
|
1745
|
+
info(' npx playwright install chromium');
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
// Update gitignore - evidence runs should not be committed
|
|
1749
|
+
updateGitignore();
|
|
1750
|
+
|
|
1751
|
+
updateMetadata(
|
|
1752
|
+
{
|
|
1753
|
+
features: {
|
|
1754
|
+
browserqa: {
|
|
1755
|
+
enabled: true,
|
|
1756
|
+
version,
|
|
1757
|
+
at: new Date().toISOString(),
|
|
1758
|
+
playwright_detected: playwrightAvailable,
|
|
1759
|
+
},
|
|
1760
|
+
},
|
|
1761
|
+
},
|
|
1762
|
+
version
|
|
1763
|
+
);
|
|
1764
|
+
|
|
1765
|
+
success('UI Testing enabled (agentic browser testing + visual verification)');
|
|
1766
|
+
info('Evidence directory: .agileflow/ui-review/');
|
|
1767
|
+
info('Screenshots directory: screenshots/ (for visual verification with VISUAL=true)');
|
|
1768
|
+
info('Spec template: .agileflow/ui-review/specs/_template.yaml');
|
|
1769
|
+
info('Agentic testing: /agileflow:browser-qa SCENARIO=<spec.yaml>');
|
|
1770
|
+
info('Visual verification: /agileflow:babysit EPIC=EP-XXXX MODE=loop VISUAL=true');
|
|
1771
|
+
if (playwrightAvailable) {
|
|
1772
|
+
info('Playwright: detected');
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
return true;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1484
1778
|
const CLAUDE_MD_MARKER = '<!-- AGILEFLOW_BABYSIT_RULES -->';
|
|
1485
1779
|
const CLAUDE_MD_CONTENT = `
|
|
1486
1780
|
|