agentweaver 0.1.13 → 0.1.15

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.
Files changed (51) hide show
  1. package/README.md +24 -19
  2. package/dist/artifacts.js +6 -1
  3. package/dist/doctor/checks/cwd-context.js +4 -3
  4. package/dist/doctor/checks/env-diagnostics.js +168 -71
  5. package/dist/doctor/checks/flow-readiness.js +210 -198
  6. package/dist/doctor/index.js +1 -1
  7. package/dist/doctor/orchestrator.js +18 -7
  8. package/dist/doctor/runner.js +9 -8
  9. package/dist/doctor/types.js +12 -0
  10. package/dist/index.js +119 -55
  11. package/dist/interactive-ui.js +25 -25
  12. package/dist/pipeline/declarative-flows.js +1 -0
  13. package/dist/pipeline/flow-catalog.js +4 -0
  14. package/dist/pipeline/flow-specs/auto-common.json +1 -0
  15. package/dist/pipeline/flow-specs/auto-golang.json +2 -1
  16. package/dist/pipeline/flow-specs/bugz/bug-analyze.json +1 -0
  17. package/dist/pipeline/flow-specs/bugz/bug-fix.json +1 -0
  18. package/dist/pipeline/flow-specs/design-review.json +239 -0
  19. package/dist/pipeline/flow-specs/git-commit.json +1 -0
  20. package/dist/pipeline/flow-specs/gitlab/gitlab-diff-review.json +3 -2
  21. package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +3 -2
  22. package/dist/pipeline/flow-specs/gitlab/mr-description.json +1 -0
  23. package/dist/pipeline/flow-specs/go/run-go-linter-loop.json +3 -2
  24. package/dist/pipeline/flow-specs/go/run-go-tests-loop.json +3 -2
  25. package/dist/pipeline/flow-specs/implement.json +13 -0
  26. package/dist/pipeline/flow-specs/plan-revise.json +261 -0
  27. package/dist/pipeline/flow-specs/plan.json +2 -1
  28. package/dist/pipeline/flow-specs/review/review-fix.json +1 -0
  29. package/dist/pipeline/flow-specs/review/review-loop.json +1 -0
  30. package/dist/pipeline/flow-specs/review/review-project.json +1 -0
  31. package/dist/pipeline/flow-specs/review/review.json +2 -1
  32. package/dist/pipeline/flow-specs/task-describe.json +67 -8
  33. package/dist/pipeline/node-registry.js +8 -0
  34. package/dist/pipeline/nodes/ensure-summary-json-node.js +59 -0
  35. package/dist/pipeline/nodes/git-commit-node.js +1 -1
  36. package/dist/pipeline/nodes/git-status-node.js +1 -1
  37. package/dist/pipeline/nodes/review-findings-form-node.js +8 -8
  38. package/dist/pipeline/nodes/user-input-node.js +2 -2
  39. package/dist/pipeline/prompt-registry.js +3 -1
  40. package/dist/pipeline/spec-types.js +2 -0
  41. package/dist/pipeline/value-resolver.js +11 -1
  42. package/dist/prompts.js +49 -2
  43. package/dist/runtime/design-review-input-contract.js +112 -0
  44. package/dist/runtime/plan-revise-input-contract.js +144 -0
  45. package/dist/runtime/process-runner.js +2 -2
  46. package/dist/runtime/ready-to-merge.js +10 -0
  47. package/dist/scope.js +13 -4
  48. package/dist/structured-artifact-schema-registry.js +1 -0
  49. package/dist/structured-artifact-schemas.json +117 -0
  50. package/dist/structured-artifacts.js +6 -0
  51. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import { existsSync, readFileSync } from "node:fs";
3
3
  import path from "node:path";
4
4
  import process from "node:process";
5
5
  import { fileURLToPath } from "node:url";
6
- import { REVIEW_FILE_RE, bugAnalyzeArtifacts, bugAnalyzeJsonFile, bugFixDesignJsonFile, bugFixPlanJsonFile, designJsonFile, gitlabDiffFile, gitlabDiffJsonFile, ensureScopeWorkspaceDir, gitlabReviewFile, gitlabReviewJsonFile, latestArtifactIteration, nextArtifactIteration, planJsonFile, planArtifacts, qaJsonFile, readyToMergeFile, requireArtifacts, reviewAssessmentFile, reviewAssessmentJsonFile, reviewFile, reviewFixSelectionJsonFile, reviewJsonFile, scopeWorkspaceDir, flowStateFile, taskSummaryFile, } from "./artifacts.js";
6
+ import { bugAnalyzeArtifacts, bugAnalyzeJsonFile, bugFixDesignJsonFile, bugFixPlanJsonFile, designReviewFile, designReviewJsonFile, designJsonFile, gitlabDiffFile, gitlabDiffJsonFile, ensureScopeWorkspaceDir, gitlabReviewFile, gitlabReviewJsonFile, latestArtifactIteration, nextArtifactIteration, planJsonFile, planArtifacts, qaJsonFile, readyToMergeFile, requireArtifacts, reviewAssessmentFile, reviewAssessmentJsonFile, reviewFile, reviewFixSelectionJsonFile, reviewJsonFile, scopeWorkspaceDir, flowStateFile, taskSummaryFile, } from "./artifacts.js";
7
7
  import { FlowInterruptedError, TaskRunnerError } from "./errors.js";
8
8
  import { createFlowRunState, hasResumableFlowState, loadFlowRunState, prepareFlowStateForResume, resetFlowRunState, rewindFlowRunStateToPhase, saveFlowRunState, stripExecutionStatePayload, } from "./flow-state.js";
9
9
  import { requireJiraTaskFile } from "./jira.js";
@@ -20,11 +20,14 @@ import { resolveCmd } from "./runtime/command-resolution.js";
20
20
  import { loadTieredEnv } from "./runtime/env-loader.js";
21
21
  import { agentweaverHome } from "./runtime/agentweaver-home.js";
22
22
  import { runCommand } from "./runtime/process-runner.js";
23
+ import { resolveDesignReviewInputContract } from "./runtime/design-review-input-contract.js";
24
+ import { resolvePlanReviseInputContract } from "./runtime/plan-revise-input-contract.js";
25
+ import { clearReadyToMergeFile } from "./runtime/ready-to-merge.js";
23
26
  import { InteractiveUi } from "./interactive-ui.js";
24
27
  import { bye, printError, printInfo, printPanel, printSummary, setFlowExecutionState, stripAnsi, } from "./tui.js";
25
28
  import { requestUserInputInTerminal } from "./user-input.js";
26
29
  import { runDoctorCommand } from "./doctor/index.js";
27
- import { attachJiraContext, detectGitBranchName, requestJiraContext, resolveProjectScope, } from "./scope.js";
30
+ import { detectGitBranchName, requestJiraContext, resolveProjectScope, } from "./scope.js";
28
31
  const COMMANDS = [
29
32
  "auto-golang",
30
33
  "auto-common",
@@ -32,12 +35,14 @@ const COMMANDS = [
32
35
  "auto-reset",
33
36
  "bug-analyze",
34
37
  "bug-fix",
38
+ "design-review",
35
39
  "doctor",
36
40
  "git-commit",
37
41
  "gitlab-diff-review",
38
42
  "gitlab-review",
39
43
  "mr-description",
40
44
  "plan",
45
+ "plan-revise",
41
46
  "task-describe",
42
47
  "implement",
43
48
  "review",
@@ -84,7 +89,7 @@ function formatProcessFailure(error) {
84
89
  if (!preview) {
85
90
  return baseMessage;
86
91
  }
87
- return `${baseMessage}\nПричина:\n${preview}`;
92
+ return `${baseMessage}\nReason:\n${preview}`;
88
93
  }
89
94
  function escapeRegExp(value) {
90
95
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -99,9 +104,11 @@ function usage() {
99
104
  agentweaver gitlab-review [--dry] [--verbose] [--prompt <text>] [--scope <name>]
100
105
  agentweaver bug-analyze [--dry] [--verbose] [--prompt <text>] <jira-browse-url|jira-issue-key>
101
106
  agentweaver bug-fix [--dry] [--verbose] [--prompt <text>] <jira-browse-url|jira-issue-key>
107
+ agentweaver design-review [--dry] [--verbose] [--prompt <text>] <jira-browse-url|jira-issue-key>
102
108
  agentweaver doctor [<category>|<check-id>] [--json]
103
109
  agentweaver mr-description [--dry] [--verbose] [--prompt <text>] <jira-browse-url|jira-issue-key>
104
110
  agentweaver plan [--dry] [--verbose] [--prompt <text>] [--md-lang <en|ru>] [<jira-browse-url|jira-issue-key>]
111
+ agentweaver plan-revise [--dry] [--verbose] [--prompt <text>] <jira-browse-url|jira-issue-key>
105
112
  agentweaver task-describe [--dry] [--verbose] [--prompt <text>] [<jira-browse-url|jira-issue-key>]
106
113
  agentweaver implement [--dry] [--verbose] [--prompt <text>] [--scope <name>] [<jira-browse-url|jira-issue-key>]
107
114
  agentweaver review [--dry] [--verbose] [--prompt <text>] [--scope <name>] [<jira-browse-url|jira-issue-key>]
@@ -188,8 +195,8 @@ function launchProfileSelectionForm() {
188
195
  const defaultExecutor = DEFAULT_LAUNCH_PROFILE.executor;
189
196
  return {
190
197
  formId: "flow-launch-profile",
191
- title: "Настройки запуска LLM",
192
- description: `Выберите executor для запуска flow. Текущий default: ${defaultExecutor}.`,
198
+ title: "LLM Launch Settings",
199
+ description: `Select an executor for the flow. Current default: ${defaultExecutor}.`,
193
200
  submitLabel: "Continue",
194
201
  fields: [
195
202
  {
@@ -215,8 +222,8 @@ function launchModelSelectionForm(executor) {
215
222
  }));
216
223
  return {
217
224
  formId: "flow-launch-model",
218
- title: "Настройки запуска LLM",
219
- description: `Выберите модель для запуска flow. Текущий default для ${resolvedExecutor}: ${defaultModel}.`,
225
+ title: "LLM Launch Settings",
226
+ description: `Select a model for the flow. Current default for ${resolvedExecutor}: ${defaultModel}.`,
220
227
  submitLabel: "Start",
221
228
  fields: [
222
229
  {
@@ -364,17 +371,19 @@ function scopeWithRestoredJiraContext(scope, state) {
364
371
  if (scope.jiraRef || !state?.jiraRef?.trim()) {
365
372
  return scope;
366
373
  }
367
- return attachJiraContext(scope, state.jiraRef);
374
+ return resolveProjectScope(null, state.jiraRef);
375
+ }
376
+ function buildInteractiveBaseConfig(flowId, scope) {
377
+ return buildBaseConfig(flowId, {
378
+ ...(scope.jiraRef ? { jiraRef: scope.jiraRef } : {}),
379
+ });
368
380
  }
369
381
  function lookupInteractiveFlowResume(flowEntry, currentScope) {
370
382
  const directState = loadFlowRunState(currentScope.scopeKey, flowEntry.id);
371
383
  if (directState && hasResumableFlowState(directState)) {
372
384
  try {
373
385
  const effectiveScope = scopeWithRestoredJiraContext(currentScope, directState);
374
- const baseConfig = buildBaseConfig(flowEntry.id, {
375
- ...(effectiveScope.jiraRef ? { jiraRef: effectiveScope.jiraRef } : {}),
376
- scopeName: effectiveScope.scopeKey,
377
- });
386
+ const baseConfig = buildInteractiveBaseConfig(flowEntry.id, effectiveScope);
378
387
  const config = buildRuntimeConfig(baseConfig, effectiveScope);
379
388
  validateDeclarativeFlowResumeState(flowEntry, config, directState, directState.launchProfile);
380
389
  return {
@@ -410,21 +419,10 @@ function printAutoCommonPhasesHelp() {
410
419
  printPanel("Auto-Common Phases", phaseLines.join("\n"), "magenta");
411
420
  }
412
421
  function nextReviewIterationForTask(taskKey) {
413
- let maxIndex = 0;
414
- const workspaceDir = scopeWorkspaceDir(taskKey);
415
- if (!existsSync(workspaceDir)) {
416
- return 1;
417
- }
418
- for (const entry of readdirSync(workspaceDir, { withFileTypes: true })) {
419
- if (!entry.isFile()) {
420
- continue;
421
- }
422
- const match = REVIEW_FILE_RE.exec(entry.name);
423
- if (match && match[1] === taskKey) {
424
- maxIndex = Math.max(maxIndex, Number.parseInt(match[2] ?? "0", 10));
425
- }
426
- }
427
- return maxIndex + 1;
422
+ return nextArtifactIteration(taskKey, "review");
423
+ }
424
+ function nextDesignReviewIterationForTask(taskKey) {
425
+ return nextArtifactIteration(taskKey, "design-review");
428
426
  }
429
427
  function buildBaseConfig(command, options = {}) {
430
428
  return {
@@ -442,8 +440,10 @@ function buildBaseConfig(command, options = {}) {
442
440
  }
443
441
  function commandRequiresTask(command) {
444
442
  return (command === "plan" ||
443
+ command === "plan-revise" ||
445
444
  command === "bug-analyze" ||
446
445
  command === "bug-fix" ||
446
+ command === "design-review" ||
447
447
  command === "mr-description" ||
448
448
  command === "auto-golang" ||
449
449
  command === "auto-common" ||
@@ -525,32 +525,12 @@ function autoFlowParams(config, forceRefreshSummary = false) {
525
525
  runGoLinterIteration: nextArtifactIteration(config.taskKey, "run-go-linter-result", "json"),
526
526
  };
527
527
  }
528
- const FLOW_DESCRIPTIONS = {
529
- "auto-golang": "Full task pipeline: planning, implementation, checks, review, review replies, and repeated iterations until ready to merge.",
530
- "bug-analyze": "Analyzes bug from Jira and creates structured artifacts: root cause hypothesis, fix design, and implementation plan.",
531
- "git-commit": "Collects git status/diff, generates commit message via LLM, allows file selection and commit confirmation.",
532
- "gitlab-diff-review": "Requests GitLab MR URL via user-input, downloads merge request diff via API, and runs code review with markdown and structured JSON artifacts.",
533
- "gitlab-review": "Requests GitLab MR URL via user-input, downloads code review comments via API, assesses which findings are fair and proposes fixes, then runs review-fix for the selected findings.",
534
- "bug-fix": "Takes bug-analyze results as source of truth and implements the bug fix in code.",
535
- "mr-description": "Prepares a brief intent description for a merge request based on the task and current changes.",
536
- plan: "Loads task from Jira and creates design, implementation plan, and QA plan in structured JSON and markdown.",
537
- "task-describe": "Builds a brief task description either from Jira or from quick user-input without Jira.",
538
- implement: "Implements the task from approved design/plan artifacts and runs post-verify builds if needed.",
539
- review: "Runs code review of current changes and writes structured findings artifacts.",
540
- "review-fix": "Fixes issues after review-reply, updates code, and runs mandatory checks after modifications.",
541
- "review-loop": "Iteratively runs review and review-fix cycles up to 5 times until ready-to-merge is achieved.",
542
- "run-go-tests-loop": "Cycles through `./run_go_tests.py` locally, analyzes the last error, and fixes code until successful or attempts exhausted.",
543
- "run-go-linter-loop": "Cycles through `./run_go_linter.py` locally, fixes linter or generation issues, and retries until success.",
544
- };
545
- function flowDescription(id) {
546
- return FLOW_DESCRIPTIONS[id] ?? "Описание для этого flow пока не задано.";
547
- }
548
528
  function interactiveFlowDefinition(entry) {
549
529
  const flow = entry.flow;
550
530
  return {
551
531
  id: entry.id,
552
532
  label: entry.id,
553
- description: flowDescription(entry.id),
533
+ description: flow.description ?? "No description available for this flow.",
554
534
  source: entry.source,
555
535
  treePath: [...entry.treePath],
556
536
  ...(entry.source === "project-local" ? { sourcePath: entry.absolutePath } : {}),
@@ -885,6 +865,90 @@ async function executeCommand(baseConfig, runFollowupVerify = true, requestUserI
885
865
  }, launchProfile ? { launchProfile } : {}, requestUserInput, setSummary, launchMode, runtime);
886
866
  return false;
887
867
  }
868
+ if (config.command === "design-review") {
869
+ const iteration = nextDesignReviewIterationForTask(config.taskKey);
870
+ const inputContract = resolveDesignReviewInputContract(config.taskKey);
871
+ if (!config.dryRun) {
872
+ clearReadyToMergeFile(config.taskKey);
873
+ }
874
+ await runDeclarativeFlowBySpecFile("design-review.json", config, {
875
+ taskKey: config.taskKey,
876
+ iteration,
877
+ planningIteration: inputContract.planningIteration,
878
+ designFile: inputContract.designFile,
879
+ designJsonFile: inputContract.designJsonFile,
880
+ planFile: inputContract.planFile,
881
+ planJsonFile: inputContract.planJsonFile,
882
+ hasQaArtifacts: inputContract.hasQaArtifacts,
883
+ qaFilePath: inputContract.qaFilePath,
884
+ qaJsonFilePath: inputContract.qaJsonFilePath,
885
+ qaFile: inputContract.qaFile,
886
+ qaJsonFile: inputContract.qaJsonFile,
887
+ hasJiraTaskFile: inputContract.hasJiraTaskFile,
888
+ jiraTaskFilePath: inputContract.jiraTaskFilePath,
889
+ jiraTaskFile: inputContract.jiraTaskFile,
890
+ hasJiraAttachmentsManifestFile: inputContract.hasJiraAttachmentsManifestFile,
891
+ jiraAttachmentsManifestFilePath: inputContract.jiraAttachmentsManifestFilePath,
892
+ jiraAttachmentsManifestFile: inputContract.jiraAttachmentsManifestFile,
893
+ hasJiraAttachmentsContextFile: inputContract.hasJiraAttachmentsContextFile,
894
+ jiraAttachmentsContextFilePath: inputContract.jiraAttachmentsContextFilePath,
895
+ jiraAttachmentsContextFile: inputContract.jiraAttachmentsContextFile,
896
+ hasPlanningAnswersJsonFile: inputContract.hasPlanningAnswersJsonFile,
897
+ planningAnswersJsonFilePath: inputContract.planningAnswersJsonFilePath,
898
+ planningAnswersJsonFile: inputContract.planningAnswersJsonFile,
899
+ extraPrompt: config.extraPrompt,
900
+ }, launchProfile ? { launchProfile } : {}, requestUserInput, undefined, launchMode, runtime);
901
+ if (!config.dryRun) {
902
+ printSummary("Design Review", `Artifacts:\n${designReviewFile(config.taskKey, iteration)}\n${designReviewJsonFile(config.taskKey, iteration)}`);
903
+ }
904
+ return false;
905
+ }
906
+ if (config.command === "plan-revise") {
907
+ const inputContract = resolvePlanReviseInputContract(config.taskKey);
908
+ if (!config.dryRun) {
909
+ clearReadyToMergeFile(config.taskKey);
910
+ }
911
+ await runDeclarativeFlowBySpecFile("plan-revise.json", config, {
912
+ taskKey: config.taskKey,
913
+ reviewIteration: inputContract.reviewIteration,
914
+ reviewFile: inputContract.reviewFile,
915
+ reviewJsonFile: inputContract.reviewJsonFile,
916
+ sourcePlanningIteration: inputContract.sourcePlanningIteration,
917
+ outputIteration: inputContract.outputIteration,
918
+ designFile: inputContract.designFile,
919
+ designJsonFile: inputContract.designJsonFile,
920
+ planFile: inputContract.planFile,
921
+ planJsonFile: inputContract.planJsonFile,
922
+ hasQaArtifacts: inputContract.hasQaArtifacts,
923
+ qaFilePath: inputContract.qaFilePath,
924
+ qaJsonFilePath: inputContract.qaJsonFilePath,
925
+ qaFile: inputContract.qaFile,
926
+ qaJsonFile: inputContract.qaJsonFile,
927
+ revisedDesignFile: inputContract.revisedDesignFile,
928
+ revisedDesignJsonFile: inputContract.revisedDesignJsonFile,
929
+ revisedPlanFile: inputContract.revisedPlanFile,
930
+ revisedPlanJsonFile: inputContract.revisedPlanJsonFile,
931
+ revisedQaFile: inputContract.revisedQaFile,
932
+ revisedQaJsonFile: inputContract.revisedQaJsonFile,
933
+ hasJiraTaskFile: inputContract.hasJiraTaskFile,
934
+ jiraTaskFilePath: inputContract.jiraTaskFilePath,
935
+ jiraTaskFile: inputContract.jiraTaskFile,
936
+ hasJiraAttachmentsManifestFile: inputContract.hasJiraAttachmentsManifestFile,
937
+ jiraAttachmentsManifestFilePath: inputContract.jiraAttachmentsManifestFilePath,
938
+ jiraAttachmentsManifestFile: inputContract.jiraAttachmentsManifestFile,
939
+ hasJiraAttachmentsContextFile: inputContract.hasJiraAttachmentsContextFile,
940
+ jiraAttachmentsContextFilePath: inputContract.jiraAttachmentsContextFilePath,
941
+ jiraAttachmentsContextFile: inputContract.jiraAttachmentsContextFile,
942
+ hasPlanningAnswersJsonFile: inputContract.hasPlanningAnswersJsonFile,
943
+ planningAnswersJsonFilePath: inputContract.planningAnswersJsonFilePath,
944
+ planningAnswersJsonFile: inputContract.planningAnswersJsonFile,
945
+ extraPrompt: config.extraPrompt,
946
+ }, launchProfile ? { launchProfile } : {}, requestUserInput, undefined, launchMode, runtime);
947
+ if (!config.dryRun) {
948
+ printSummary("Plan Revise", `Artifacts:\n${inputContract.revisedDesignFile}\n${inputContract.revisedDesignJsonFile}\n${inputContract.revisedPlanFile}\n${inputContract.revisedPlanJsonFile}\n${inputContract.revisedQaFile}\n${inputContract.revisedQaJsonFile}`);
949
+ }
950
+ return false;
951
+ }
888
952
  if (config.command === "gitlab-review") {
889
953
  const iteration = nextReviewIterationForTask(config.taskKey);
890
954
  const gitlabReviewIteration = nextArtifactIteration(config.taskKey, "gitlab-review");
@@ -1202,17 +1266,14 @@ async function runInteractive(jiraRef, forceRefresh = false, scopeName) {
1202
1266
  throw new TaskRunnerError("Resume is impossible because launch profile was not saved. Use restart.");
1203
1267
  }
1204
1268
  const previousScopeKey = currentScope.scopeKey;
1205
- const baseConfig = buildBaseConfig(flowId, {
1206
- ...(currentScope.jiraRef ? { jiraRef: currentScope.jiraRef } : {}),
1207
- scopeName: currentScope.scopeKey,
1208
- });
1269
+ const baseConfig = buildInteractiveBaseConfig(flowId, currentScope);
1209
1270
  if (flowEntry.source === "built-in" && isBuiltInCommandFlowId(flowId)) {
1210
1271
  const nextScope = await resolveScopeForCommand(baseConfig, (form) => ui.requestUserInput(form));
1211
1272
  currentScope = nextScope;
1212
1273
  }
1213
1274
  else if (flowRequiresTaskScope(flowEntry) && !currentScope.jiraRef) {
1214
1275
  const jiraContext = await requestJiraContext((form) => ui.requestUserInput(form));
1215
- currentScope = attachJiraContext(currentScope, jiraContext.jiraRef);
1276
+ currentScope = resolveProjectScope(null, jiraContext.jiraRef);
1216
1277
  }
1217
1278
  ui.setScope(currentScope.scopeKey, currentScope.jiraIssueKey ?? null);
1218
1279
  if (previousScopeKey !== currentScope.scopeKey || currentScope.jiraIssueKey) {
@@ -1303,7 +1364,10 @@ export async function main(argv = process.argv.slice(2)) {
1303
1364
  return await runInteractive(args[0] ?? "", forceRefresh);
1304
1365
  }
1305
1366
  const parsedArgs = parseCliArgs(args);
1306
- await executeCommand(buildConfigFromArgs(parsedArgs));
1367
+ const commandCompleted = await executeCommand(buildConfigFromArgs(parsedArgs));
1368
+ if (parsedArgs.command === "doctor") {
1369
+ return commandCompleted ? 0 : 1;
1370
+ }
1307
1371
  return 0;
1308
1372
  }
1309
1373
  catch (error) {
@@ -213,7 +213,7 @@ export class InteractiveUi {
213
213
  top: 3,
214
214
  left: 0,
215
215
  width: "34%",
216
- height: "50%-1",
216
+ height: "50%-4",
217
217
  tags: true,
218
218
  label: " Current Flow ",
219
219
  padding: {
@@ -232,10 +232,10 @@ export class InteractiveUi {
232
232
  });
233
233
  this.flowList = blessed.list({
234
234
  parent: this.screen,
235
- top: "50%+2",
235
+ top: "50%-1",
236
236
  left: 0,
237
237
  width: "34%",
238
- bottom: 11,
238
+ bottom: 14,
239
239
  keys: true,
240
240
  vi: true,
241
241
  mouse: true,
@@ -395,7 +395,7 @@ export class InteractiveUi {
395
395
  bottom: 6,
396
396
  left: 0,
397
397
  width: "34%",
398
- height: 5,
398
+ height: 8,
399
399
  tags: true,
400
400
  label: " Flow Description ",
401
401
  padding: {
@@ -806,19 +806,19 @@ export class InteractiveUi {
806
806
  this.help.setContent(renderMarkdownToTerminal([
807
807
  "AgentWeaver interactive mode",
808
808
  "",
809
- "Клавиши:",
810
- "Up / Down выбрать папку или flow",
811
- "Right раскрыть папку",
812
- "Left свернуть папку или перейти к родителю",
813
- "Enter раскрыть папку или открыть запуск flow",
814
- "Enter подтвердить запуск в модалке",
815
- "Esc закрыть help/модалку или прервать running flow",
816
- "F1 открыть или закрыть help",
817
- "Tab переключить pane",
818
- "Ctrl+L очистить лог",
819
- "q / Ctrl+C выйти",
809
+ "Keys:",
810
+ "Up / Down select folder or flow",
811
+ "Right expand folder",
812
+ "Left collapse folder or go to parent",
813
+ "Enter expand folder or launch flow",
814
+ "Enter confirm launch in modal",
815
+ "Esc close help/modal or interrupt running flow",
816
+ "F1 open or close help",
817
+ "Tab switch pane",
818
+ "Ctrl+L clear log",
819
+ "q / Ctrl+C exit",
820
820
  "",
821
- "Доступные flow:",
821
+ "Available flows:",
822
822
  ...this.options.flows.map((flow) => flow.treePath.join("/")),
823
823
  ].join("\n")));
824
824
  this.footer.setContent(" Up/Down: select | Left/Right: fold | Enter: toggle/run | Esc: close/interrupt | h: help | Tab: switch pane | q: exit ");
@@ -1522,20 +1522,20 @@ export class InteractiveUi {
1522
1522
  if (selectedItem.kind === "folder") {
1523
1523
  const kindLabel = selectedItem.pathSegments[0] === "custom" ? "project-local" : "built-in";
1524
1524
  const folderDescription = [
1525
- `Папка flow \`${selectedItem.pathSegments.join("/")}\`.`,
1525
+ `Flow folder \`${selectedItem.pathSegments.join("/")}\`.`,
1526
1526
  "",
1527
- `Источник: ${kindLabel}`,
1528
- `Статус: ${this.expandedFlowFolders.has(selectedItem.key) ? "развёрнута" : "свёрнута"}`,
1527
+ `Source: ${kindLabel}`,
1528
+ `State: ${this.expandedFlowFolders.has(selectedItem.key) ? "expanded" : "collapsed"}`,
1529
1529
  ].join("\n");
1530
1530
  this.description.setContent(renderMarkdownToTerminal(stripAnsi(folderDescription)));
1531
1531
  return;
1532
1532
  }
1533
1533
  const { flow } = selectedItem;
1534
- const description = flow.description?.trim() || "Описание для этого flow пока не задано.";
1534
+ const description = flow.description?.trim() || "No description available for this flow.";
1535
1535
  const details = [
1536
- `Путь: ${flow.treePath.join("/")}`,
1537
- `Источник: ${flow.source === "project-local" ? "project-local" : "built-in"}`,
1538
- flow.source === "project-local" && flow.sourcePath ? `Файл: ${flow.sourcePath}` : "",
1536
+ `Path: ${flow.treePath.join("/")}`,
1537
+ `Source: ${flow.source === "project-local" ? "project-local" : "built-in"}`,
1538
+ flow.source === "project-local" && flow.sourcePath ? `File: ${flow.sourcePath}` : "",
1539
1539
  ]
1540
1540
  .filter((line) => line.length > 0)
1541
1541
  .join("\n");
@@ -1579,7 +1579,7 @@ export class InteractiveUi {
1579
1579
  renderProgress() {
1580
1580
  const flow = this.progressFlowDefinition();
1581
1581
  if (!flow) {
1582
- this.progress.setContent("Выберите конкретный flow в дереве, чтобы увидеть его прогресс.");
1582
+ this.progress.setContent("Select a flow in the tree to see its progress.");
1583
1583
  return;
1584
1584
  }
1585
1585
  const flowState = this.flowState.flowId === flow.id
@@ -1932,7 +1932,7 @@ export class InteractiveUi {
1932
1932
  flowId,
1933
1933
  resumeAvailable: true,
1934
1934
  hasExistingState: true,
1935
- details: "Текущий flow будет остановлен. Состояние сохранится, и его можно будет продолжить через Resume.",
1935
+ details: "The current flow will be stopped. State will be saved and can be continued via Resume.",
1936
1936
  selectedAction: "stop",
1937
1937
  };
1938
1938
  this.renderConfirm();
@@ -28,6 +28,7 @@ export function loadDeclarativeFlow(flow) {
28
28
  const loaded = {
29
29
  kind: spec.kind,
30
30
  version: spec.version,
31
+ ...(spec.description !== undefined ? { description: spec.description } : {}),
31
32
  constants: spec.constants ?? {},
32
33
  phases,
33
34
  source: ref.source,
@@ -8,11 +8,13 @@ export const BUILT_IN_COMMAND_FLOW_IDS = [
8
8
  "auto-common",
9
9
  "bug-analyze",
10
10
  "bug-fix",
11
+ "design-review",
11
12
  "git-commit",
12
13
  "gitlab-diff-review",
13
14
  "gitlab-review",
14
15
  "mr-description",
15
16
  "plan",
17
+ "plan-revise",
16
18
  "task-describe",
17
19
  "implement",
18
20
  "review",
@@ -26,11 +28,13 @@ const BUILT_IN_COMMAND_FLOW_FILES = {
26
28
  "auto-common": "auto-common.json",
27
29
  "bug-analyze": "bugz/bug-analyze.json",
28
30
  "bug-fix": "bugz/bug-fix.json",
31
+ "design-review": "design-review.json",
29
32
  "git-commit": "git-commit.json",
30
33
  "gitlab-diff-review": "gitlab/gitlab-diff-review.json",
31
34
  "gitlab-review": "gitlab/gitlab-review.json",
32
35
  "mr-description": "gitlab/mr-description.json",
33
36
  plan: "plan.json",
37
+ "plan-revise": "plan-revise.json",
34
38
  "task-describe": "task-describe.json",
35
39
  implement: "implement.json",
36
40
  review: "review/review.json",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "kind": "auto-flow",
3
3
  "version": 1,
4
+ "description": "End-to-end resumable pipeline without language-specific checks. Runs: plan (with Jira fetch and Q&A) → implement → review loop. Simplified alternative to auto-golang for projects that do not need Go linter/test loops.",
4
5
  "phases": [
5
6
  {
6
7
  "id": "plan",
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "kind": "auto-flow",
3
3
  "version": 1,
4
+ "description": "End-to-end resumable pipeline for Go projects. Runs the full sequence: plan (with Jira fetch and Q&A) → implement → linter loop → test loop → review loop → final linter loop → final test loop. Supports --from to restart from a specific phase and auto-status/auto-reset for state management.",
4
5
  "constants": {
5
- "autoReviewFixExtraPrompt": "Исправлять только блокеры, критикалы и важные"
6
+ "autoReviewFixExtraPrompt": "Fix only blockers, criticals, and important findings"
6
7
  },
7
8
  "phases": [
8
9
  {
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "kind": "bug-analyze-flow",
3
3
  "version": 1,
4
+ "description": "Fetches a Bug-type Jira issue, validates the issue type, generates or reuses a cached task summary, and produces structured bug analysis: root cause hypothesis, fix design, and step-by-step fix plan.",
4
5
  "phases": [
5
6
  {
6
7
  "id": "bug_analyze",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "kind": "bug-fix-flow",
3
3
  "version": 1,
4
+ "description": "Applies the fix designed in bug-analyze. Uses the root cause hypothesis, fix design, and fix plan artifacts as the source of truth to implement code changes locally.",
4
5
  "phases": [
5
6
  {
6
7
  "id": "bug_fix",