agentweaver 0.1.14 → 0.1.16
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 +29 -7
- package/dist/artifact-manifest.js +219 -0
- package/dist/artifacts.js +21 -1
- package/dist/doctor/checks/cwd-context.js +4 -3
- package/dist/doctor/checks/env-diagnostics.js +193 -71
- package/dist/doctor/checks/flow-readiness.js +212 -203
- package/dist/doctor/index.js +1 -1
- package/dist/doctor/orchestrator.js +18 -7
- package/dist/doctor/runner.js +9 -8
- package/dist/doctor/types.js +12 -0
- package/dist/flow-state.js +75 -15
- package/dist/index.js +499 -199
- package/dist/interactive/blessed-session.js +361 -0
- package/dist/interactive/controller.js +1293 -0
- package/dist/interactive/create-interactive-session.js +5 -0
- package/dist/interactive/ink/index.js +576 -0
- package/dist/interactive/progress.js +245 -0
- package/dist/interactive/selectors.js +14 -0
- package/dist/interactive/session.js +1 -0
- package/dist/interactive/state.js +34 -0
- package/dist/interactive/tree.js +155 -0
- package/dist/interactive/types.js +1 -0
- package/dist/interactive/view-model.js +1 -0
- package/dist/interactive-ui.js +159 -194
- package/dist/pipeline/context.js +1 -0
- package/dist/pipeline/declarative-flow-runner.js +212 -6
- package/dist/pipeline/declarative-flows.js +27 -0
- package/dist/pipeline/execution-routing-config.js +15 -0
- package/dist/pipeline/flow-catalog.js +23 -3
- package/dist/pipeline/flow-run-resume.js +29 -0
- package/dist/pipeline/flow-specs/auto-common.json +89 -360
- package/dist/pipeline/flow-specs/auto-golang.json +58 -363
- package/dist/pipeline/flow-specs/auto-simple.json +141 -0
- package/dist/pipeline/flow-specs/bugz/bug-analyze.json +2 -0
- package/dist/pipeline/flow-specs/bugz/bug-fix.json +1 -0
- package/dist/pipeline/flow-specs/design-review/design-review-loop.json +304 -0
- package/dist/pipeline/flow-specs/design-review.json +249 -0
- package/dist/pipeline/flow-specs/gitlab/gitlab-diff-review.json +11 -0
- package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +2 -0
- package/dist/pipeline/flow-specs/gitlab/mr-description.json +1 -0
- package/dist/pipeline/flow-specs/go/run-go-linter-loop.json +2 -0
- package/dist/pipeline/flow-specs/go/run-go-tests-loop.json +2 -0
- package/dist/pipeline/flow-specs/implement.json +24 -5
- package/dist/pipeline/flow-specs/instant-task.json +177 -0
- package/dist/pipeline/flow-specs/normalize-task-source.json +311 -0
- package/dist/pipeline/flow-specs/plan-revise.json +267 -0
- package/dist/pipeline/flow-specs/plan.json +48 -70
- package/dist/pipeline/flow-specs/review/review-fix.json +24 -4
- package/dist/pipeline/flow-specs/review/review-loop.json +351 -45
- package/dist/pipeline/flow-specs/review/review-project-loop.json +590 -0
- package/dist/pipeline/flow-specs/review/review-project.json +12 -0
- package/dist/pipeline/flow-specs/review/review.json +37 -31
- package/dist/pipeline/flow-specs/task-describe.json +62 -2
- package/dist/pipeline/flow-specs/task-source/jira-fetch.json +70 -0
- package/dist/pipeline/flow-specs/task-source/manual-input.json +216 -0
- package/dist/pipeline/node-registry.js +49 -1
- package/dist/pipeline/node-runner.js +3 -2
- package/dist/pipeline/nodes/build-review-fix-prompt-node.js +5 -1
- package/dist/pipeline/nodes/clear-ready-to-merge-node.js +11 -0
- package/dist/pipeline/nodes/commit-message-form-node.js +8 -0
- package/dist/pipeline/nodes/design-review-verdict-node.js +36 -0
- package/dist/pipeline/nodes/ensure-summary-json-node.js +70 -0
- package/dist/pipeline/nodes/fetch-gitlab-diff-node.js +19 -2
- package/dist/pipeline/nodes/fetch-gitlab-review-node.js +19 -2
- package/dist/pipeline/nodes/flow-run-node.js +226 -7
- package/dist/pipeline/nodes/git-commit-form-node.js +8 -0
- package/dist/pipeline/nodes/gitlab-review-artifacts-node.js +19 -2
- package/dist/pipeline/nodes/jira-fetch-node.js +50 -4
- package/dist/pipeline/nodes/llm-prompt-node.js +32 -12
- package/dist/pipeline/nodes/planning-bundle-node.js +10 -0
- package/dist/pipeline/nodes/review-verdict-node.js +86 -0
- package/dist/pipeline/nodes/select-files-form-node.js +8 -0
- package/dist/pipeline/nodes/structured-summary-node.js +24 -0
- package/dist/pipeline/nodes/user-input-node.js +38 -3
- package/dist/pipeline/nodes/write-selection-file-node.js +20 -4
- package/dist/pipeline/prompt-registry.js +5 -1
- package/dist/pipeline/prompt-runtime.js +4 -1
- package/dist/pipeline/review-iteration.js +26 -0
- package/dist/pipeline/spec-compiler.js +2 -0
- package/dist/pipeline/spec-types.js +5 -0
- package/dist/pipeline/spec-validator.js +14 -0
- package/dist/pipeline/value-resolver.js +84 -1
- package/dist/prompts.js +82 -13
- package/dist/review-severity.js +45 -0
- package/dist/runtime/artifact-registry.js +402 -0
- package/dist/runtime/design-review-input-contract.js +113 -0
- package/dist/runtime/env-loader.js +3 -0
- package/dist/runtime/execution-routing-store.js +134 -0
- package/dist/runtime/execution-routing.js +227 -0
- package/dist/runtime/interactive-execution-routing.js +462 -0
- package/dist/runtime/plan-revise-input-contract.js +147 -0
- package/dist/runtime/planning-bundle.js +123 -0
- package/dist/runtime/ready-to-merge.js +31 -0
- package/dist/runtime/review-input-contract.js +100 -0
- package/dist/scope.js +11 -2
- package/dist/structured-artifact-schema-registry.js +10 -0
- package/dist/structured-artifact-schemas.json +257 -1
- package/dist/structured-artifacts.js +83 -6
- package/dist/user-input.js +70 -3
- package/package.json +6 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { TaskRunnerError } from "./errors.js";
|
|
3
|
-
import { STRUCTURED_ARTIFACT_SCHEMA_IDS, getStructuredArtifactSchema, } from "./structured-artifact-schema-registry.js";
|
|
4
|
-
export { STRUCTURED_ARTIFACT_SCHEMA_IDS };
|
|
3
|
+
import { ARTIFACT_PAYLOAD_SCHEMA_IDS, STRUCTURED_ARTIFACT_SCHEMA_IDS, getStructuredArtifactSchema, } from "./structured-artifact-schema-registry.js";
|
|
4
|
+
export { ARTIFACT_PAYLOAD_SCHEMA_IDS, STRUCTURED_ARTIFACT_SCHEMA_IDS };
|
|
5
5
|
function isRecord(value) {
|
|
6
6
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
7
|
}
|
|
@@ -11,9 +11,19 @@ function schemaLabel(node) {
|
|
|
11
11
|
}
|
|
12
12
|
switch (node.type) {
|
|
13
13
|
case "string":
|
|
14
|
+
if (node.enum && node.enum.length > 0) {
|
|
15
|
+
return `one of: ${node.enum.join(", ")}`;
|
|
16
|
+
}
|
|
17
|
+
if (node.pattern) {
|
|
18
|
+
return "a string with the expected format";
|
|
19
|
+
}
|
|
14
20
|
return node.nonEmpty ? "a non-empty string" : "a string";
|
|
15
21
|
case "boolean":
|
|
16
22
|
return "a boolean";
|
|
23
|
+
case "bytes":
|
|
24
|
+
return "a binary file";
|
|
25
|
+
case "json":
|
|
26
|
+
return "valid JSON";
|
|
17
27
|
case "number":
|
|
18
28
|
return "a number";
|
|
19
29
|
case "null":
|
|
@@ -43,9 +53,27 @@ function validateNode(value, schema, currentPath) {
|
|
|
43
53
|
if (typeof value !== "string" || (schema.nonEmpty && value.trim().length === 0)) {
|
|
44
54
|
return [`${currentPath} must be ${schemaLabel(schema)}`];
|
|
45
55
|
}
|
|
56
|
+
if (schema.enum && !schema.enum.includes(value)) {
|
|
57
|
+
return [`${currentPath} must be ${schemaLabel(schema)}`];
|
|
58
|
+
}
|
|
59
|
+
if (schema.pattern) {
|
|
60
|
+
try {
|
|
61
|
+
const pattern = new RegExp(schema.pattern);
|
|
62
|
+
if (!pattern.test(value)) {
|
|
63
|
+
return [`${currentPath} must be ${schemaLabel(schema)}`];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return [`${currentPath} uses an invalid schema pattern`];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
46
70
|
return [];
|
|
47
71
|
case "boolean":
|
|
48
72
|
return typeof value === "boolean" ? [] : [`${currentPath} must be a boolean`];
|
|
73
|
+
case "bytes":
|
|
74
|
+
return value instanceof Uint8Array ? [] : [`${currentPath} must be a binary file`];
|
|
75
|
+
case "json":
|
|
76
|
+
return validateJsonValue(value, currentPath);
|
|
49
77
|
case "number":
|
|
50
78
|
return typeof value === "number" && !Number.isNaN(value) ? [] : [`${currentPath} must be a number`];
|
|
51
79
|
case "null":
|
|
@@ -79,6 +107,28 @@ function validateNode(value, schema, currentPath) {
|
|
|
79
107
|
}
|
|
80
108
|
}
|
|
81
109
|
}
|
|
110
|
+
function validateJsonValue(value, currentPath) {
|
|
111
|
+
if (value === null ||
|
|
112
|
+
typeof value === "string" ||
|
|
113
|
+
typeof value === "boolean" ||
|
|
114
|
+
(typeof value === "number" && Number.isFinite(value))) {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
if (Array.isArray(value)) {
|
|
118
|
+
return value.flatMap((item, index) => validateJsonValue(item, `${currentPath}[${index}]`));
|
|
119
|
+
}
|
|
120
|
+
if (!isRecord(value)) {
|
|
121
|
+
return [`${currentPath} must be valid JSON`];
|
|
122
|
+
}
|
|
123
|
+
return Object.entries(value).flatMap(([key, candidate]) => validateJsonValue(candidate, `${currentPath}.${key}`));
|
|
124
|
+
}
|
|
125
|
+
function validateArtifactPayloadValue(value, schemaId, label = "$") {
|
|
126
|
+
const schema = getStructuredArtifactSchema(schemaId);
|
|
127
|
+
const issues = validateNode(value, schema, label);
|
|
128
|
+
if (issues.length > 0) {
|
|
129
|
+
throw new TaskRunnerError(`Structured artifact ${label} failed schema ${schemaId} validation:\n${issues.join("\n")}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
82
132
|
export function validateStructuredArtifact(path, schemaId) {
|
|
83
133
|
if (!existsSync(path)) {
|
|
84
134
|
throw new TaskRunnerError(`Structured artifact file not found: ${path}`);
|
|
@@ -90,11 +140,38 @@ export function validateStructuredArtifact(path, schemaId) {
|
|
|
90
140
|
catch (error) {
|
|
91
141
|
throw new TaskRunnerError(`Structured artifact ${path} is not valid JSON: ${error.message}`);
|
|
92
142
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
143
|
+
validateArtifactPayloadValue(parsed, schemaId, path);
|
|
144
|
+
}
|
|
145
|
+
export function validateStructuredArtifactValue(value, schemaId, label = "$") {
|
|
146
|
+
validateArtifactPayloadValue(value, schemaId, label);
|
|
147
|
+
}
|
|
148
|
+
export function isArtifactPayloadSchemaId(schemaId) {
|
|
149
|
+
return ARTIFACT_PAYLOAD_SCHEMA_IDS.includes(schemaId);
|
|
150
|
+
}
|
|
151
|
+
export function validateArtifactPayload(path, schemaId) {
|
|
152
|
+
if (!existsSync(path)) {
|
|
153
|
+
throw new TaskRunnerError(`Structured artifact file not found: ${path}`);
|
|
154
|
+
}
|
|
155
|
+
if (schemaId === "markdown/v1" || schemaId === "plain-text/v1") {
|
|
156
|
+
validateArtifactPayloadValue(readFileSync(path, "utf8"), schemaId, path);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (schemaId === "helper-json/v1") {
|
|
160
|
+
let parsed;
|
|
161
|
+
try {
|
|
162
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
throw new TaskRunnerError(`Structured artifact ${path} is not valid JSON: ${error.message}`);
|
|
166
|
+
}
|
|
167
|
+
validateArtifactPayloadValue(parsed, schemaId, path);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (schemaId === "opaque-file/v1") {
|
|
171
|
+
validateArtifactPayloadValue(readFileSync(path), schemaId, path);
|
|
172
|
+
return;
|
|
97
173
|
}
|
|
174
|
+
validateStructuredArtifact(path, schemaId);
|
|
98
175
|
}
|
|
99
176
|
export function validateStructuredArtifacts(items, message) {
|
|
100
177
|
try {
|
package/dist/user-input.js
CHANGED
|
@@ -19,6 +19,69 @@ export function defaultValueForField(field) {
|
|
|
19
19
|
export function buildInitialUserInputValues(fields) {
|
|
20
20
|
return Object.fromEntries(fields.map((field) => [field.id, defaultValueForField(field)]));
|
|
21
21
|
}
|
|
22
|
+
export function applyInitialUserInputValues(fields, initialValues) {
|
|
23
|
+
if (!initialValues) {
|
|
24
|
+
return fields;
|
|
25
|
+
}
|
|
26
|
+
return fields.map((field) => {
|
|
27
|
+
const initialValue = initialValues[field.id];
|
|
28
|
+
if (initialValue === undefined) {
|
|
29
|
+
return field;
|
|
30
|
+
}
|
|
31
|
+
if (field.type === "boolean" && typeof initialValue === "boolean") {
|
|
32
|
+
return { ...field, default: initialValue };
|
|
33
|
+
}
|
|
34
|
+
if (field.type === "text" && typeof initialValue === "string") {
|
|
35
|
+
return { ...field, default: initialValue };
|
|
36
|
+
}
|
|
37
|
+
if (field.type === "single-select" && typeof initialValue === "string") {
|
|
38
|
+
return { ...field, default: initialValue };
|
|
39
|
+
}
|
|
40
|
+
if (field.type === "multi-select"
|
|
41
|
+
&& Array.isArray(initialValue)
|
|
42
|
+
&& initialValue.every((item) => typeof item === "string")) {
|
|
43
|
+
return { ...field, default: [...initialValue] };
|
|
44
|
+
}
|
|
45
|
+
return field;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function defaultSelectValue(field) {
|
|
49
|
+
if (field.type === "single-select") {
|
|
50
|
+
return field.default ?? field.options[0]?.value ?? "";
|
|
51
|
+
}
|
|
52
|
+
return [...(field.default ?? [])];
|
|
53
|
+
}
|
|
54
|
+
export function resolveFieldOptions(field, values) {
|
|
55
|
+
return field.optionsFromValues?.(values) ?? field.options;
|
|
56
|
+
}
|
|
57
|
+
export function resolveFieldDefinition(field, values) {
|
|
58
|
+
if (field.type !== "single-select" && field.type !== "multi-select") {
|
|
59
|
+
return field;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...field,
|
|
63
|
+
options: resolveFieldOptions(field, values),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function normalizeUserInputFieldValue(field, values) {
|
|
67
|
+
if (field.type !== "single-select" && field.type !== "multi-select") {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const allowedValues = new Set(resolveFieldOptions(field, values).map((option) => option.value));
|
|
71
|
+
if (field.type === "single-select") {
|
|
72
|
+
const currentValue = typeof values[field.id] === "string" ? String(values[field.id]) : "";
|
|
73
|
+
if (!allowedValues.has(currentValue)) {
|
|
74
|
+
const fallback = defaultSelectValue(resolveFieldDefinition(field, values));
|
|
75
|
+
values[field.id] = typeof fallback === "string" ? fallback : "";
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const currentValue = values[field.id];
|
|
80
|
+
const currentValues = Array.isArray(currentValue)
|
|
81
|
+
? currentValue.filter((item) => typeof item === "string")
|
|
82
|
+
: [];
|
|
83
|
+
values[field.id] = currentValues.filter((item) => typeof item === "string" && allowedValues.has(item));
|
|
84
|
+
}
|
|
22
85
|
export function validateUserInputValues(form, values) {
|
|
23
86
|
for (const field of form.fields) {
|
|
24
87
|
const value = values[field.id];
|
|
@@ -38,24 +101,26 @@ export function validateUserInputValues(form, values) {
|
|
|
38
101
|
continue;
|
|
39
102
|
}
|
|
40
103
|
if (field.type === "single-select") {
|
|
104
|
+
const options = resolveFieldOptions(field, values);
|
|
41
105
|
if (typeof value !== "string") {
|
|
42
106
|
throw new TaskRunnerError(`Field '${field.label}' must be a string.`);
|
|
43
107
|
}
|
|
44
108
|
if (field.required && normalizeText(value).length === 0) {
|
|
45
109
|
throw new TaskRunnerError(`Field '${field.label}' is required.`);
|
|
46
110
|
}
|
|
47
|
-
if (value && !
|
|
111
|
+
if (value && !options.some((option) => option.value === value)) {
|
|
48
112
|
throw new TaskRunnerError(`Field '${field.label}' contains an unknown option '${value}'.`);
|
|
49
113
|
}
|
|
50
114
|
continue;
|
|
51
115
|
}
|
|
116
|
+
const options = resolveFieldOptions(field, values);
|
|
52
117
|
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
53
118
|
throw new TaskRunnerError(`Field '${field.label}' must be a string array.`);
|
|
54
119
|
}
|
|
55
120
|
if (field.required && value.length === 0) {
|
|
56
121
|
throw new TaskRunnerError(`Field '${field.label}' requires at least one selected option.`);
|
|
57
122
|
}
|
|
58
|
-
const allowed = new Set(
|
|
123
|
+
const allowed = new Set(options.map((option) => option.value));
|
|
59
124
|
for (const item of value) {
|
|
60
125
|
if (!allowed.has(item)) {
|
|
61
126
|
throw new TaskRunnerError(`Field '${field.label}' contains an unknown option '${item}'.`);
|
|
@@ -113,7 +178,9 @@ export async function requestUserInputInTerminal(form) {
|
|
|
113
178
|
process.stdout.write(`${form.description.trim()}\n`);
|
|
114
179
|
}
|
|
115
180
|
const values = buildInitialUserInputValues(form.fields);
|
|
116
|
-
for (const
|
|
181
|
+
for (const rawField of form.fields) {
|
|
182
|
+
normalizeUserInputFieldValue(rawField, values);
|
|
183
|
+
const field = resolveFieldDefinition(rawField, values);
|
|
117
184
|
if (field.type === "boolean") {
|
|
118
185
|
while (true) {
|
|
119
186
|
const current = values[field.id];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentweaver",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "CLI orchestrator for Jira/Codex engineering workflows",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -51,13 +51,16 @@
|
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "^20.17.30",
|
|
54
|
+
"@types/react": "^18.3.12",
|
|
54
55
|
"@types/semver": "^7.7.1",
|
|
55
56
|
"ts-node": "^10.9.2",
|
|
56
|
-
"typescript": "^5.8.3"
|
|
57
|
+
"typescript": "^5.8.3",
|
|
58
|
+
"vitest": "^4.1.4"
|
|
57
59
|
},
|
|
58
60
|
"dependencies": {
|
|
61
|
+
"ink": "^5.2.1",
|
|
59
62
|
"markdown-it": "^14.1.1",
|
|
60
|
-
"
|
|
63
|
+
"react": "^18.3.1",
|
|
61
64
|
"semver": "^7.7.4"
|
|
62
65
|
}
|
|
63
66
|
}
|