agentweaver 0.1.10 → 0.1.11
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/README.md +218 -224
- package/dist/artifacts.js +100 -55
- package/dist/executors/{codex-local-executor.js → codex-executor.js} +4 -4
- package/dist/executors/configs/{codex-local-config.js → codex-config.js} +1 -1
- package/dist/executors/configs/jira-fetch-config.js +2 -0
- package/dist/executors/configs/telegram-notifier-config.js +3 -0
- package/dist/executors/fetch-gitlab-diff-executor.js +1 -1
- package/dist/executors/fetch-gitlab-review-executor.js +1 -1
- package/dist/executors/git-commit-executor.js +25 -0
- package/dist/executors/telegram-notifier-executor.js +54 -0
- package/dist/flow-state.js +46 -1
- package/dist/gitlab.js +13 -8
- package/dist/index.js +469 -514
- package/dist/interactive-ui.js +144 -43
- package/dist/jira.js +52 -5
- package/dist/pipeline/auto-flow.js +6 -6
- package/dist/pipeline/context.js +1 -0
- package/dist/pipeline/flow-catalog.js +34 -4
- package/dist/pipeline/flow-model-settings.js +77 -0
- package/dist/pipeline/flow-specs/auto-common.json +446 -0
- package/dist/pipeline/flow-specs/auto-golang.json +563 -0
- package/dist/pipeline/flow-specs/{bug-analyze.json → bugz/bug-analyze.json} +43 -25
- package/dist/pipeline/flow-specs/{bug-fix.json → bugz/bug-fix.json} +5 -4
- package/dist/pipeline/flow-specs/git-commit.json +196 -0
- package/dist/pipeline/flow-specs/{gitlab-diff-review.json → gitlab/gitlab-diff-review.json} +20 -50
- package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +165 -0
- package/dist/pipeline/flow-specs/{mr-description.json → gitlab/mr-description.json} +17 -10
- package/dist/pipeline/flow-specs/{run-go-linter-loop.json → go/run-go-linter-loop.json} +40 -14
- package/dist/pipeline/flow-specs/{run-go-tests-loop.json → go/run-go-tests-loop.json} +40 -14
- package/dist/pipeline/flow-specs/implement.json +5 -4
- package/dist/pipeline/flow-specs/plan.json +40 -148
- package/dist/pipeline/flow-specs/{review-fix.json → review/review-fix.json} +73 -13
- package/dist/pipeline/flow-specs/review/review-loop.json +280 -0
- package/dist/pipeline/flow-specs/review/review-project.json +87 -0
- package/dist/pipeline/flow-specs/review/review.json +126 -0
- package/dist/pipeline/flow-specs/task-describe.json +191 -11
- package/dist/pipeline/launch-profile-config.js +38 -0
- package/dist/pipeline/node-registry.js +75 -45
- package/dist/pipeline/nodes/build-failure-summary-node.js +16 -29
- package/dist/pipeline/nodes/build-review-fix-prompt-node.js +36 -0
- package/dist/pipeline/nodes/codex-prompt-node.js +41 -0
- package/dist/pipeline/nodes/commit-message-form-node.js +79 -0
- package/dist/pipeline/nodes/git-commit-form-node.js +138 -0
- package/dist/pipeline/nodes/git-commit-node.js +28 -0
- package/dist/pipeline/nodes/git-status-node.js +221 -0
- package/dist/pipeline/nodes/gitlab-review-artifacts-node.js +10 -6
- package/dist/pipeline/nodes/jira-context-node.js +10 -0
- package/dist/pipeline/nodes/llm-prompt-node.js +62 -0
- package/dist/pipeline/nodes/plan-codex-node.js +1 -1
- package/dist/pipeline/nodes/read-file-node.js +11 -0
- package/dist/pipeline/nodes/review-findings-form-node.js +18 -14
- package/dist/pipeline/nodes/select-files-form-node.js +72 -0
- package/dist/pipeline/nodes/telegram-notifier-node.js +28 -0
- package/dist/pipeline/nodes/user-input-node.js +29 -8
- package/dist/pipeline/nodes/write-selection-file-node.js +46 -0
- package/dist/pipeline/prompt-registry.js +2 -4
- package/dist/pipeline/prompt-runtime.js +13 -3
- package/dist/pipeline/registry.js +6 -8
- package/dist/pipeline/spec-compiler.js +5 -0
- package/dist/pipeline/spec-types.js +7 -3
- package/dist/pipeline/spec-validator.js +4 -0
- package/dist/pipeline/types.js +1 -0
- package/dist/pipeline/value-resolver.js +40 -38
- package/dist/prompts.js +104 -110
- package/dist/runtime/agentweaver-home.js +8 -0
- package/dist/runtime/command-resolution.js +0 -38
- package/dist/runtime/env-loader.js +43 -0
- package/dist/structured-artifact-schema-registry.js +53 -0
- package/dist/structured-artifact-schemas.json +0 -20
- package/dist/structured-artifacts.js +3 -43
- package/dist/user-input.js +30 -2
- package/package.json +2 -6
- package/Dockerfile.codex +0 -56
- package/dist/executors/claude-executor.js +0 -46
- package/dist/executors/codex-docker-executor.js +0 -27
- package/dist/executors/configs/claude-config.js +0 -12
- package/dist/executors/configs/codex-docker-config.js +0 -10
- package/dist/executors/configs/verify-build-config.js +0 -7
- package/dist/executors/verify-build-executor.js +0 -123
- package/dist/pipeline/flow-specs/auto.json +0 -979
- package/dist/pipeline/flow-specs/gitlab-review.json +0 -317
- package/dist/pipeline/flow-specs/opencode/auto-opencode.json +0 -1365
- package/dist/pipeline/flow-specs/opencode/bugz/bug-analyze-opencode.json +0 -382
- package/dist/pipeline/flow-specs/opencode/bugz/bug-fix-opencode.json +0 -56
- package/dist/pipeline/flow-specs/opencode/gitlab/gitlab-diff-review-opencode.json +0 -308
- package/dist/pipeline/flow-specs/opencode/gitlab/gitlab-review-opencode.json +0 -437
- package/dist/pipeline/flow-specs/opencode/gitlab/mr-description-opencode.json +0 -117
- package/dist/pipeline/flow-specs/opencode/go/run-go-linter-loop-opencode.json +0 -321
- package/dist/pipeline/flow-specs/opencode/go/run-go-tests-loop-opencode.json +0 -321
- package/dist/pipeline/flow-specs/opencode/implement-opencode.json +0 -64
- package/dist/pipeline/flow-specs/opencode/plan-opencode.json +0 -603
- package/dist/pipeline/flow-specs/opencode/review/review-fix-opencode.json +0 -209
- package/dist/pipeline/flow-specs/opencode/review/review-opencode.json +0 -452
- package/dist/pipeline/flow-specs/opencode/task-describe-opencode.json +0 -148
- package/dist/pipeline/flow-specs/review-project.json +0 -243
- package/dist/pipeline/flow-specs/review.json +0 -312
- package/dist/pipeline/flows/preflight-flow.js +0 -19
- package/dist/pipeline/nodes/claude-prompt-node.js +0 -54
- package/dist/pipeline/nodes/codex-docker-prompt-node.js +0 -32
- package/dist/pipeline/nodes/codex-local-prompt-node.js +0 -32
- package/dist/pipeline/nodes/review-claude-node.js +0 -38
- package/dist/pipeline/nodes/review-reply-codex-node.js +0 -40
- package/dist/pipeline/nodes/verify-build-node.js +0 -15
- package/dist/runtime/docker-runtime.js +0 -51
- package/docker-compose.yml +0 -445
- package/verify_build.sh +0 -105
package/dist/interactive-ui.js
CHANGED
|
@@ -142,6 +142,7 @@ export class InteractiveUi {
|
|
|
142
142
|
scopeKey;
|
|
143
143
|
jiraIssueKey;
|
|
144
144
|
summaryVisible;
|
|
145
|
+
version;
|
|
145
146
|
constructor(options) {
|
|
146
147
|
this.options = options;
|
|
147
148
|
if (options.flows.length === 0) {
|
|
@@ -149,12 +150,13 @@ export class InteractiveUi {
|
|
|
149
150
|
}
|
|
150
151
|
this.flowMap = new Map(options.flows.map((flow) => [flow.id, flow]));
|
|
151
152
|
this.flowTree = buildFlowTree(options.flows);
|
|
152
|
-
this.selectedFlowId = options.flows[0]?.id ?? "auto";
|
|
153
|
+
this.selectedFlowId = options.flows[0]?.id ?? "auto-golang";
|
|
153
154
|
this.visibleFlowItems = this.computeVisibleFlowItems();
|
|
154
155
|
this.selectedFlowItemKey = this.visibleFlowItems[0]?.key ?? makeFlowKey(this.selectedFlowId);
|
|
155
156
|
this.scopeKey = options.scopeKey;
|
|
156
157
|
this.jiraIssueKey = options.jiraIssueKey ?? null;
|
|
157
158
|
this.summaryVisible = options.summaryText.trim().length > 0;
|
|
159
|
+
this.version = options.version ?? "";
|
|
158
160
|
this.screen = blessed.screen({
|
|
159
161
|
smartCSR: true,
|
|
160
162
|
fullUnicode: true,
|
|
@@ -721,10 +723,12 @@ export class InteractiveUi {
|
|
|
721
723
|
const branchLabel = this.options.gitBranchName ? this.options.gitBranchName : "detached-head";
|
|
722
724
|
const flowLabel = `${current}${this.busy ? " {yellow-fg}[running]{/yellow-fg}" : ""}`;
|
|
723
725
|
const divider = " {gray-fg}│{/gray-fg} ";
|
|
726
|
+
const versionLabel = this.version ? `${divider}{bold}Version{/bold} {white-fg}${this.version}{/white-fg}` : "";
|
|
724
727
|
this.header.setContent([
|
|
725
728
|
"{bold}AgentWeaver{/bold}",
|
|
726
729
|
divider,
|
|
727
730
|
`{bold}Scope{/bold} {green-fg}${this.scopeKey}{/green-fg}`,
|
|
731
|
+
versionLabel,
|
|
728
732
|
this.jiraIssueKey ? `${divider}{bold}Jira{/bold} {yellow-fg}${this.jiraIssueKey}{/yellow-fg}` : "",
|
|
729
733
|
divider,
|
|
730
734
|
`{bold}Flow{/bold} ${flowLabel}`,
|
|
@@ -745,19 +749,117 @@ export class InteractiveUi {
|
|
|
745
749
|
}
|
|
746
750
|
return this.activeFormSession.form.fields[this.activeFormSession.currentFieldIndex] ?? null;
|
|
747
751
|
}
|
|
748
|
-
renderTextInputValue(value, placeholder) {
|
|
749
|
-
const
|
|
750
|
-
const
|
|
752
|
+
renderTextInputValue(value, placeholder, rows = 1) {
|
|
753
|
+
const rawLines = (value || placeholder || "Введите текст").split("\n");
|
|
754
|
+
const visibleLines = rawLines.slice(0, Math.max(1, rows));
|
|
755
|
+
const contentWidth = visibleLines.reduce((max, line) => Math.max(max, line.length), 0);
|
|
756
|
+
const frameWidth = Math.max(36, contentWidth + 6);
|
|
751
757
|
const innerWidth = Math.max(32, frameWidth - 4);
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
758
|
+
const renderedRows = Array.from({ length: Math.max(1, rows) }, (_, index) => {
|
|
759
|
+
const rawLine = visibleLines[index] ?? "";
|
|
760
|
+
const visibleText = rawLine.length > innerWidth - 2 ? `${rawLine.slice(0, innerWidth - 5)}...` : rawLine;
|
|
761
|
+
const color = value ? "white-fg" : "gray-fg";
|
|
762
|
+
return `{cyan-fg}│{/cyan-fg}{black-bg} ${index === 0 ? "{green-fg}>{/green-fg}" : " "} {${color}}${visibleText.padEnd(innerWidth - 2, " ")}{/${color}} {/black-bg}{cyan-fg}│{/cyan-fg}`;
|
|
763
|
+
});
|
|
764
|
+
return [`{cyan-fg}┌${"─".repeat(frameWidth - 2)}┐{/cyan-fg}`, ...renderedRows, `{cyan-fg}└${"─".repeat(frameWidth - 2)}┘{/cyan-fg}`];
|
|
765
|
+
}
|
|
766
|
+
formModalInnerHeight() {
|
|
767
|
+
const rawHeight = typeof this.formModal.height === "number" ? this.formModal.height : this.formModal?.lpos?.yi
|
|
768
|
+
? this.formModal.lpos.yl - this.formModal.lpos.yi + 1
|
|
769
|
+
: 0;
|
|
770
|
+
const paddingTop = Number(this.formModal.padding?.top ?? 0);
|
|
771
|
+
const paddingBottom = Number(this.formModal.padding?.bottom ?? 0);
|
|
772
|
+
return Math.max(6, rawHeight - 2 - paddingTop - paddingBottom);
|
|
773
|
+
}
|
|
774
|
+
formModalInnerWidth() {
|
|
775
|
+
const rawWidth = typeof this.formModal.width === "number" ? this.formModal.width : this.formModal?.lpos?.xi
|
|
776
|
+
? this.formModal.lpos.xl - this.formModal.lpos.xi + 1
|
|
777
|
+
: 0;
|
|
778
|
+
const paddingLeft = Number(this.formModal.padding?.left ?? 0);
|
|
779
|
+
const paddingRight = Number(this.formModal.padding?.right ?? 0);
|
|
780
|
+
return Math.max(24, rawWidth - 2 - paddingLeft - paddingRight);
|
|
781
|
+
}
|
|
782
|
+
wrapFormText(text, width) {
|
|
783
|
+
const normalized = text.trim();
|
|
784
|
+
if (!normalized) {
|
|
785
|
+
return [""];
|
|
786
|
+
}
|
|
787
|
+
const wrapped = [];
|
|
788
|
+
for (const paragraph of normalized.split("\n")) {
|
|
789
|
+
if (!paragraph.trim()) {
|
|
790
|
+
wrapped.push("");
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
let remaining = paragraph.trim();
|
|
794
|
+
while (remaining.length > width) {
|
|
795
|
+
let splitAt = remaining.lastIndexOf(" ", width);
|
|
796
|
+
if (splitAt <= 0) {
|
|
797
|
+
splitAt = width;
|
|
798
|
+
}
|
|
799
|
+
wrapped.push(remaining.slice(0, splitAt).trimEnd());
|
|
800
|
+
remaining = remaining.slice(splitAt).trimStart();
|
|
801
|
+
}
|
|
802
|
+
wrapped.push(remaining);
|
|
803
|
+
}
|
|
804
|
+
return wrapped.length > 0 ? wrapped : [""];
|
|
805
|
+
}
|
|
806
|
+
renderSelectableFieldWindow(field, value, currentOptionIndex, availableLines) {
|
|
807
|
+
const contentWidth = this.formModalInnerWidth();
|
|
808
|
+
const firstLineWidth = Math.max(12, contentWidth - 6);
|
|
809
|
+
const continuationWidth = Math.max(8, contentWidth - 6);
|
|
810
|
+
const descriptionWidth = Math.max(8, contentWidth - 4);
|
|
811
|
+
const renderedOptions = field.options.map((option, index) => {
|
|
812
|
+
const isCursor = index === currentOptionIndex;
|
|
813
|
+
const isSelected = field.type === "single-select"
|
|
814
|
+
? value === option.value
|
|
815
|
+
: Array.isArray(value) && value.includes(option.value);
|
|
816
|
+
const cursor = isCursor ? "{cyan-fg}>{/cyan-fg}" : " ";
|
|
817
|
+
const marker = isSelected ? "[x]" : "[ ]";
|
|
818
|
+
const labelLines = this.wrapFormText(option.label, firstLineWidth);
|
|
819
|
+
const itemLines = [`${cursor} ${marker} ${labelLines[0] ?? ""}`];
|
|
820
|
+
for (const continuation of labelLines.slice(1)) {
|
|
821
|
+
itemLines.push(` ${continuation.slice(0, continuationWidth)}`);
|
|
822
|
+
}
|
|
823
|
+
if (option.description?.trim()) {
|
|
824
|
+
for (const descriptionLine of this.wrapFormText(option.description, descriptionWidth)) {
|
|
825
|
+
itemLines.push(` {gray-fg}${descriptionLine}{/gray-fg}`);
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return itemLines;
|
|
829
|
+
});
|
|
830
|
+
if (renderedOptions.length === 0) {
|
|
831
|
+
return ["{gray-fg}Нет доступных вариантов.{/gray-fg}"];
|
|
832
|
+
}
|
|
833
|
+
let startIndex = 0;
|
|
834
|
+
let selectedStartLine = 0;
|
|
835
|
+
for (let index = 0; index < currentOptionIndex; index += 1) {
|
|
836
|
+
selectedStartLine += renderedOptions[index]?.length ?? 0;
|
|
837
|
+
}
|
|
838
|
+
let visibleLines = 0;
|
|
839
|
+
for (let index = 0; index < renderedOptions.length; index += 1) {
|
|
840
|
+
const itemHeight = renderedOptions[index]?.length ?? 0;
|
|
841
|
+
if (index < currentOptionIndex && selectedStartLine + itemHeight > availableLines) {
|
|
842
|
+
startIndex = index + 1;
|
|
843
|
+
selectedStartLine -= itemHeight;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
const output = [];
|
|
847
|
+
for (let index = startIndex; index < renderedOptions.length; index += 1) {
|
|
848
|
+
const itemLines = renderedOptions[index] ?? [];
|
|
849
|
+
if (output.length > 0 && output.length + itemLines.length > availableLines) {
|
|
850
|
+
break;
|
|
851
|
+
}
|
|
852
|
+
if (output.length === 0 && itemLines.length > availableLines) {
|
|
853
|
+
output.push(...itemLines.slice(0, availableLines));
|
|
854
|
+
break;
|
|
855
|
+
}
|
|
856
|
+
output.push(...itemLines);
|
|
857
|
+
visibleLines += itemLines.length;
|
|
858
|
+
if (visibleLines >= availableLines) {
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
return output;
|
|
761
863
|
}
|
|
762
864
|
renderActiveForm() {
|
|
763
865
|
if (!this.activeFormSession) {
|
|
@@ -771,18 +873,20 @@ export class InteractiveUi {
|
|
|
771
873
|
if (!field) {
|
|
772
874
|
return;
|
|
773
875
|
}
|
|
774
|
-
const
|
|
876
|
+
const headerLines = [`{bold}${session.form.title}{/bold}`];
|
|
775
877
|
if (session.form.description?.trim()) {
|
|
776
|
-
|
|
777
|
-
|
|
878
|
+
headerLines.push("");
|
|
879
|
+
headerLines.push(session.form.description.trim());
|
|
778
880
|
}
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
881
|
+
headerLines.push("");
|
|
882
|
+
headerLines.push(`Field ${session.currentFieldIndex + 1}/${session.form.fields.length}`);
|
|
883
|
+
headerLines.push(`{yellow-fg}${field.label}{/yellow-fg}`);
|
|
782
884
|
if (field.help?.trim()) {
|
|
783
|
-
|
|
885
|
+
headerLines.push(field.help.trim());
|
|
784
886
|
}
|
|
785
|
-
|
|
887
|
+
headerLines.push("");
|
|
888
|
+
const footerLines = ["", "{green-fg}Ctrl+S{/green-fg}: submit", "{magenta-fg}Shift+Tab{/magenta-fg}: previous field", "{red-fg}Esc{/red-fg}: cancel"];
|
|
889
|
+
const lines = [...headerLines];
|
|
786
890
|
if (field.type === "boolean") {
|
|
787
891
|
const current = session.values[field.id] === true;
|
|
788
892
|
lines.push(`${current ? "[x]" : "[ ]"} ${field.label}`);
|
|
@@ -792,37 +896,24 @@ export class InteractiveUi {
|
|
|
792
896
|
}
|
|
793
897
|
else if (field.type === "text") {
|
|
794
898
|
const current = String(session.values[field.id] ?? "");
|
|
795
|
-
lines.push(...this.renderTextInputValue(current, field.placeholder));
|
|
899
|
+
lines.push(...this.renderTextInputValue(current, field.placeholder, field.multiline ? Math.max(1, field.rows ?? 3) : 1));
|
|
796
900
|
lines.push("");
|
|
797
|
-
lines.push("Type text, Backspace: delete");
|
|
798
|
-
lines.push("
|
|
901
|
+
lines.push(field.multiline ? "Type text, Enter: new line, Backspace: delete" : "Type text, Backspace: delete");
|
|
902
|
+
lines.push("Tab: next field");
|
|
799
903
|
}
|
|
800
904
|
else {
|
|
801
905
|
const currentOptionIndex = Math.min(session.currentOptionIndex, Math.max(0, field.options.length - 1));
|
|
802
906
|
session.currentOptionIndex = currentOptionIndex;
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
const value = session.values[field.id];
|
|
806
|
-
const isSelected = field.type === "single-select"
|
|
807
|
-
? value === option.value
|
|
808
|
-
: Array.isArray(value) && value.includes(option.value);
|
|
809
|
-
const cursor = isCursor ? "{cyan-fg}>{/cyan-fg}" : " ";
|
|
810
|
-
const marker = isSelected ? "[x]" : "[ ]";
|
|
811
|
-
lines.push(`${cursor} ${marker} ${option.label}`);
|
|
812
|
-
if (option.description?.trim()) {
|
|
813
|
-
lines.push(` {gray-fg}${option.description.trim()}{/gray-fg}`);
|
|
814
|
-
}
|
|
815
|
-
});
|
|
907
|
+
const availableLines = Math.max(3, this.formModalInnerHeight() - headerLines.length - footerLines.length - 3);
|
|
908
|
+
lines.push(...this.renderSelectableFieldWindow(field, session.values[field.id], currentOptionIndex, availableLines));
|
|
816
909
|
lines.push("");
|
|
817
910
|
lines.push("Up/Down: move");
|
|
818
911
|
lines.push("Space: select/toggle");
|
|
819
912
|
lines.push("Enter/Tab: next field");
|
|
820
913
|
}
|
|
821
|
-
lines.push(
|
|
822
|
-
lines.push("{green-fg}Ctrl+S{/green-fg}: submit");
|
|
823
|
-
lines.push("{magenta-fg}Shift+Tab{/magenta-fg}: previous field");
|
|
824
|
-
lines.push("{red-fg}Esc{/red-fg}: cancel");
|
|
914
|
+
lines.push(...footerLines);
|
|
825
915
|
this.formModal.setContent(lines.join("\n"));
|
|
916
|
+
this.formModal.setScroll(0);
|
|
826
917
|
this.formModal.show();
|
|
827
918
|
this.formModal.setFront();
|
|
828
919
|
this.formModal.focus();
|
|
@@ -880,7 +971,7 @@ export class InteractiveUi {
|
|
|
880
971
|
this.renderActiveForm();
|
|
881
972
|
}
|
|
882
973
|
}
|
|
883
|
-
appendActiveFormText(ch, key) {
|
|
974
|
+
appendActiveFormText(ch, key, appendNewline = false) {
|
|
884
975
|
const session = this.activeFormSession;
|
|
885
976
|
const field = this.currentFormField();
|
|
886
977
|
if (!session || !field || field.type !== "text") {
|
|
@@ -892,6 +983,11 @@ export class InteractiveUi {
|
|
|
892
983
|
this.renderActiveForm();
|
|
893
984
|
return;
|
|
894
985
|
}
|
|
986
|
+
if (appendNewline) {
|
|
987
|
+
session.values[field.id] = `${current}\n`;
|
|
988
|
+
this.renderActiveForm();
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
895
991
|
if (key.ctrl || key.meta || !ch || ch === "\r" || ch === "\n" || ch === "\t") {
|
|
896
992
|
return;
|
|
897
993
|
}
|
|
@@ -966,7 +1062,12 @@ export class InteractiveUi {
|
|
|
966
1062
|
}
|
|
967
1063
|
if (field.type === "text") {
|
|
968
1064
|
if (key.name === "enter") {
|
|
969
|
-
|
|
1065
|
+
if (field.multiline) {
|
|
1066
|
+
this.appendActiveFormText(ch, key, true);
|
|
1067
|
+
}
|
|
1068
|
+
else {
|
|
1069
|
+
this.moveActiveFormField(1);
|
|
1070
|
+
}
|
|
970
1071
|
return;
|
|
971
1072
|
}
|
|
972
1073
|
this.appendActiveFormText(ch, key);
|
package/dist/jira.js
CHANGED
|
@@ -5,6 +5,57 @@ import { TaskRunnerError } from "./errors.js";
|
|
|
5
5
|
const ISSUE_KEY_RE = /^[A-Z][A-Z0-9_]*-[0-9]+$/;
|
|
6
6
|
const TEXT_ATTACHMENT_EXTENSIONS = new Set([".md", ".json", ".txt"]);
|
|
7
7
|
const DOWNLOAD_ONLY_ATTACHMENT_EXTENSIONS = new Set([".doc"]);
|
|
8
|
+
const JIRA_AUTH_MODES = new Set(["auto", "basic", "bearer"]);
|
|
9
|
+
function parseJiraAuthMode(rawMode) {
|
|
10
|
+
const mode = rawMode?.trim().toLowerCase() || "auto";
|
|
11
|
+
if (!JIRA_AUTH_MODES.has(mode)) {
|
|
12
|
+
throw new TaskRunnerError("JIRA_AUTH_MODE must be one of: auto, basic, bearer.");
|
|
13
|
+
}
|
|
14
|
+
return mode;
|
|
15
|
+
}
|
|
16
|
+
export function detectJiraDeployment(url) {
|
|
17
|
+
try {
|
|
18
|
+
return new URL(url).hostname.toLowerCase().includes("atlassian") ? "cloud" : "server";
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return url.toLowerCase().includes("atlassian") ? "cloud" : "server";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function resolveJiraAuthMode(url) {
|
|
25
|
+
const authMode = parseJiraAuthMode(process.env.JIRA_AUTH_MODE);
|
|
26
|
+
if (authMode !== "auto") {
|
|
27
|
+
return authMode;
|
|
28
|
+
}
|
|
29
|
+
return detectJiraDeployment(url) === "cloud" ? "basic" : "bearer";
|
|
30
|
+
}
|
|
31
|
+
export function buildJiraAuthHeaders(url) {
|
|
32
|
+
const jiraApiKey = process.env.JIRA_API_KEY?.trim();
|
|
33
|
+
if (!jiraApiKey) {
|
|
34
|
+
throw new TaskRunnerError("JIRA_API_KEY is required for Jira authentication.");
|
|
35
|
+
}
|
|
36
|
+
const authMode = resolveJiraAuthMode(url);
|
|
37
|
+
if (authMode === "bearer") {
|
|
38
|
+
return {
|
|
39
|
+
Authorization: `Bearer ${jiraApiKey}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const jiraUsername = process.env.JIRA_USERNAME?.trim();
|
|
43
|
+
if (!jiraUsername) {
|
|
44
|
+
const host = (() => {
|
|
45
|
+
try {
|
|
46
|
+
return new URL(url).host;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return "unknown";
|
|
50
|
+
}
|
|
51
|
+
})();
|
|
52
|
+
throw new TaskRunnerError(`JIRA_USERNAME is required for Jira Cloud Basic auth (detected from URL host: ${host}).`);
|
|
53
|
+
}
|
|
54
|
+
const encodedCredentials = Buffer.from(`${jiraUsername}:${jiraApiKey}`).toString("base64");
|
|
55
|
+
return {
|
|
56
|
+
Authorization: `Basic ${encodedCredentials}`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
8
59
|
function sanitizeAttachmentFileName(fileName) {
|
|
9
60
|
const parsed = path.parse(fileName);
|
|
10
61
|
const baseName = parsed.name
|
|
@@ -29,13 +80,9 @@ function parseJiraAttachments(issueBody) {
|
|
|
29
80
|
}
|
|
30
81
|
}
|
|
31
82
|
async function fetchAuthorizedBuffer(url, accept) {
|
|
32
|
-
const jiraApiKey = process.env.JIRA_API_KEY;
|
|
33
|
-
if (!jiraApiKey) {
|
|
34
|
-
throw new TaskRunnerError("JIRA_API_KEY is required for Jira fetch.");
|
|
35
|
-
}
|
|
36
83
|
const response = await fetch(url, {
|
|
37
84
|
headers: {
|
|
38
|
-
|
|
85
|
+
...buildJiraAuthHeaders(url),
|
|
39
86
|
Accept: accept,
|
|
40
87
|
},
|
|
41
88
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { loadDeclarativeFlow } from "./declarative-flows.js";
|
|
2
|
-
let
|
|
3
|
-
export function
|
|
4
|
-
if (
|
|
5
|
-
return
|
|
2
|
+
let cachedAutoGolangFlow = null;
|
|
3
|
+
export function loadAutoGolangFlow() {
|
|
4
|
+
if (cachedAutoGolangFlow) {
|
|
5
|
+
return cachedAutoGolangFlow;
|
|
6
6
|
}
|
|
7
|
-
|
|
8
|
-
return
|
|
7
|
+
cachedAutoGolangFlow = loadDeclarativeFlow({ source: "built-in", fileName: "auto-golang.json" });
|
|
8
|
+
return cachedAutoGolangFlow;
|
|
9
9
|
}
|
package/dist/pipeline/context.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { TaskRunnerError } from "../errors.js";
|
|
3
|
-
import {
|
|
3
|
+
import { loadAutoGolangFlow } from "./auto-flow.js";
|
|
4
4
|
import { loadDeclarativeFlow } from "./declarative-flows.js";
|
|
5
5
|
import { listBuiltInFlowSpecFiles, listProjectFlowSpecFiles, projectFlowSpecsDir } from "./spec-loader.js";
|
|
6
6
|
export const BUILT_IN_COMMAND_FLOW_IDS = [
|
|
7
|
-
"auto",
|
|
7
|
+
"auto-golang",
|
|
8
|
+
"auto-common",
|
|
8
9
|
"bug-analyze",
|
|
9
10
|
"bug-fix",
|
|
11
|
+
"git-commit",
|
|
10
12
|
"gitlab-diff-review",
|
|
11
13
|
"gitlab-review",
|
|
12
14
|
"mr-description",
|
|
@@ -15,13 +17,41 @@ export const BUILT_IN_COMMAND_FLOW_IDS = [
|
|
|
15
17
|
"implement",
|
|
16
18
|
"review",
|
|
17
19
|
"review-fix",
|
|
20
|
+
"review-loop",
|
|
18
21
|
"run-go-tests-loop",
|
|
19
22
|
"run-go-linter-loop",
|
|
20
23
|
];
|
|
24
|
+
const BUILT_IN_COMMAND_FLOW_FILES = {
|
|
25
|
+
"auto-golang": "auto-golang.json",
|
|
26
|
+
"auto-common": "auto-common.json",
|
|
27
|
+
"bug-analyze": "bugz/bug-analyze.json",
|
|
28
|
+
"bug-fix": "bugz/bug-fix.json",
|
|
29
|
+
"git-commit": "git-commit.json",
|
|
30
|
+
"gitlab-diff-review": "gitlab/gitlab-diff-review.json",
|
|
31
|
+
"gitlab-review": "gitlab/gitlab-review.json",
|
|
32
|
+
"mr-description": "gitlab/mr-description.json",
|
|
33
|
+
plan: "plan.json",
|
|
34
|
+
"task-describe": "task-describe.json",
|
|
35
|
+
implement: "implement.json",
|
|
36
|
+
review: "review/review.json",
|
|
37
|
+
"review-fix": "review/review-fix.json",
|
|
38
|
+
"review-loop": "review/review-loop.json",
|
|
39
|
+
"run-go-tests-loop": "go/run-go-tests-loop.json",
|
|
40
|
+
"run-go-linter-loop": "go/run-go-linter-loop.json",
|
|
41
|
+
};
|
|
42
|
+
function builtInCommandIdForFile(fileName) {
|
|
43
|
+
for (const [flowId, candidate] of Object.entries(BUILT_IN_COMMAND_FLOW_FILES)) {
|
|
44
|
+
if (candidate === fileName) {
|
|
45
|
+
return flowId;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
21
50
|
function loadBuiltInCatalogEntry(fileName) {
|
|
51
|
+
const commandId = builtInCommandIdForFile(fileName);
|
|
22
52
|
const relativePath = fileName.replace(/\.json$/i, "").split(/[\\/]+/).filter((segment) => segment.length > 0);
|
|
23
|
-
const id = relativePath.join("/");
|
|
24
|
-
const flow = id === "auto" ?
|
|
53
|
+
const id = commandId ?? relativePath.join("/");
|
|
54
|
+
const flow = id === "auto-golang" ? loadAutoGolangFlow() : loadDeclarativeFlow({ source: "built-in", fileName });
|
|
25
55
|
return {
|
|
26
56
|
id,
|
|
27
57
|
source: "built-in",
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { DEFAULT_MODEL_BY_EXECUTOR, defaultModelForExecutor } from "./launch-profile-config.js";
|
|
4
|
+
import { scopeArtifactsDir } from "../artifacts.js";
|
|
5
|
+
const FLOW_MODEL_SETTINGS_FILE = "agentweaver-flow-model-settings.json";
|
|
6
|
+
function flowModelSettingsPath(scopeKey) {
|
|
7
|
+
return path.join(scopeArtifactsDir(scopeKey), FLOW_MODEL_SETTINGS_FILE);
|
|
8
|
+
}
|
|
9
|
+
function ensureArtifactsDir(scopeKey) {
|
|
10
|
+
const artifactsDir = scopeArtifactsDir(scopeKey);
|
|
11
|
+
if (!existsSync(artifactsDir)) {
|
|
12
|
+
mkdirSync(artifactsDir, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function loadFlowModelSettings(scopeKey) {
|
|
16
|
+
const filePath = flowModelSettingsPath(scopeKey);
|
|
17
|
+
if (!existsSync(filePath)) {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const content = readFileSync(filePath, "utf8");
|
|
22
|
+
const parsed = JSON.parse(content);
|
|
23
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
return parsed;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function saveFlowModelSettings(scopeKey, store) {
|
|
33
|
+
ensureArtifactsDir(scopeKey);
|
|
34
|
+
const filePath = flowModelSettingsPath(scopeKey);
|
|
35
|
+
const tempPath = `${filePath}.tmp`;
|
|
36
|
+
const content = JSON.stringify(store, null, 2);
|
|
37
|
+
writeFileSync(tempPath, content, "utf8");
|
|
38
|
+
renameSync(tempPath, filePath);
|
|
39
|
+
}
|
|
40
|
+
export function getEffectiveModelForFlow(flowId, scopeKey, executor) {
|
|
41
|
+
const store = loadFlowModelSettings(scopeKey);
|
|
42
|
+
const flowSettings = store[flowId];
|
|
43
|
+
if (!flowSettings) {
|
|
44
|
+
return defaultModelForExecutor(executor);
|
|
45
|
+
}
|
|
46
|
+
if (flowSettings.lastSelectedModel && flowSettings.lastSelectedModel !== "default") {
|
|
47
|
+
return flowSettings.lastSelectedModel;
|
|
48
|
+
}
|
|
49
|
+
if (flowSettings.defaultModel && flowSettings.defaultModel !== "default") {
|
|
50
|
+
return flowSettings.defaultModel;
|
|
51
|
+
}
|
|
52
|
+
return defaultModelForExecutor(executor);
|
|
53
|
+
}
|
|
54
|
+
export function updateLastSelectedModel(flowId, scopeKey, executor, model) {
|
|
55
|
+
const store = loadFlowModelSettings(scopeKey);
|
|
56
|
+
const existingSettings = store[flowId];
|
|
57
|
+
if (existingSettings) {
|
|
58
|
+
store[flowId] = {
|
|
59
|
+
...existingSettings,
|
|
60
|
+
executor,
|
|
61
|
+
defaultModel: model,
|
|
62
|
+
lastSelectedModel: model,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
store[flowId] = {
|
|
67
|
+
executor,
|
|
68
|
+
defaultModel: DEFAULT_MODEL_BY_EXECUTOR[executor],
|
|
69
|
+
lastSelectedModel: model,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
saveFlowModelSettings(scopeKey, store);
|
|
73
|
+
}
|
|
74
|
+
export function getFlowModelSettings(flowId, scopeKey) {
|
|
75
|
+
const store = loadFlowModelSettings(scopeKey);
|
|
76
|
+
return store[flowId] ?? null;
|
|
77
|
+
}
|