agentweaver 0.1.11 → 0.1.13

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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -0
  3. package/dist/artifacts.js +9 -0
  4. package/dist/doctor/checks/agentweaver-home.js +57 -0
  5. package/dist/doctor/checks/category.js +9 -0
  6. package/dist/doctor/checks/cwd-context.js +69 -0
  7. package/dist/doctor/checks/env-diagnostics.js +171 -0
  8. package/dist/doctor/checks/executors.js +106 -0
  9. package/dist/doctor/checks/flow-readiness.js +305 -0
  10. package/dist/doctor/checks/node-version.js +79 -0
  11. package/dist/doctor/checks/register.js +18 -0
  12. package/dist/doctor/checks/system.js +91 -0
  13. package/dist/doctor/index.js +4 -0
  14. package/dist/doctor/orchestrator.js +78 -0
  15. package/dist/doctor/registry.js +50 -0
  16. package/dist/doctor/runner.js +89 -0
  17. package/dist/doctor/types.js +12 -0
  18. package/dist/executors/codex-executor.js +2 -1
  19. package/dist/executors/jira-fetch-executor.js +1 -0
  20. package/dist/executors/opencode-executor.js +22 -11
  21. package/dist/executors/process-executor.js +3 -0
  22. package/dist/index.js +59 -35
  23. package/dist/interactive-ui.js +579 -159
  24. package/dist/jira.js +57 -0
  25. package/dist/pipeline/flow-specs/gitlab/gitlab-review.json +105 -21
  26. package/dist/pipeline/flow-specs/review/review-fix.json +1 -0
  27. package/dist/pipeline/flow-specs/review/review-loop.json +2 -0
  28. package/dist/pipeline/flow-specs/task-describe.json +64 -3
  29. package/dist/pipeline/nodes/jira-fetch-node.js +3 -0
  30. package/dist/pipeline/nodes/review-findings-form-node.js +33 -3
  31. package/dist/pipeline/nodes/user-input-node.js +18 -4
  32. package/dist/pipeline/prompt-registry.js +2 -1
  33. package/dist/pipeline/spec-types.js +2 -0
  34. package/dist/pipeline/value-resolver.js +11 -1
  35. package/dist/prompts.js +17 -2
  36. package/dist/runtime/process-runner.js +9 -3
  37. package/dist/structured-artifact-schema-registry.js +1 -0
  38. package/dist/structured-artifact-schemas.json +22 -0
  39. package/dist/user-input.js +8 -1
  40. package/package.json +4 -2
  41. package/dist/pipeline/flow-model-settings.js +0 -77
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 seko99
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -85,6 +85,7 @@ User-invokable built-in commands currently map to these flow specs:
85
85
  - `run-go-linter-loop`
86
86
  - `auto-golang`
87
87
  - `auto-common`
88
+ - `doctor`
88
89
 
89
90
  There are also built-in nested/helper flows that are loaded declaratively but are not direct top-level CLI commands, for example `review-project`.
90
91
 
@@ -215,6 +216,9 @@ agentweaver run-go-tests-loop DEMO-1234
215
216
  agentweaver run-go-linter-loop DEMO-1234
216
217
  agentweaver auto-golang DEMO-1234
217
218
  agentweaver auto-common DEMO-1234
219
+ agentweaver doctor
220
+ agentweaver doctor --json
221
+ agentweaver doctor <category>|<check-id>
218
222
  ```
219
223
 
220
224
  From a source checkout:
@@ -237,6 +241,8 @@ agentweaver auto-common --help-phases
237
241
  agentweaver auto-golang --from <phase> DEMO-1234
238
242
  agentweaver auto-status DEMO-1234
239
243
  agentweaver auto-reset DEMO-1234
244
+ agentweaver doctor
245
+ agentweaver doctor --json
240
246
  ```
241
247
 
242
248
  Notes:
package/dist/artifacts.js CHANGED
@@ -134,6 +134,9 @@ export function readyToMergeFile(taskKey) {
134
134
  export function jiraTaskFile(taskKey) {
135
135
  return taskArtifactsFile(taskKey, `${taskKey}.json`);
136
136
  }
137
+ export function jiraTaskEnrichedFile(taskKey) {
138
+ return taskArtifactsFile(taskKey, `${taskKey}-enriched.json`);
139
+ }
137
140
  export function jiraAttachmentsDir(taskKey) {
138
141
  return path.join(taskArtifactsDir(taskKey), "jira-attachments");
139
142
  }
@@ -222,6 +225,12 @@ export function reviewFixFile(taskKey, iteration) {
222
225
  export function reviewFixJsonFile(taskKey, iteration) {
223
226
  return artifactJsonFile("review-fix", taskKey, iteration);
224
227
  }
228
+ export function reviewAssessmentFile(taskKey, iteration) {
229
+ return artifactFile("review-assessment", taskKey, iteration);
230
+ }
231
+ export function reviewAssessmentJsonFile(taskKey, iteration) {
232
+ return artifactJsonFile("review-assessment", taskKey, iteration);
233
+ }
225
234
  export function reviewFixSelectionJsonFile(taskKey, iteration) {
226
235
  return artifactJsonFile("review-fix-selection", taskKey, iteration);
227
236
  }
@@ -0,0 +1,57 @@
1
+ import { accessSync, constants, existsSync } from "node:fs";
2
+ import { DoctorStatus } from "../types.js";
3
+ import { CATEGORY } from "./category.js";
4
+ import { agentweaverHome } from "../../runtime/agentweaver-home.js";
5
+ const PACKAGE_ROOT = process.cwd();
6
+ export const agentweaverHomeCheck = {
7
+ id: "agentweaver-home-01",
8
+ category: CATEGORY.AGENTWEAVER_HOME,
9
+ title: "agentweaver-home",
10
+ dependencies: [],
11
+ execute: async () => {
12
+ const homePath = agentweaverHome(PACKAGE_ROOT);
13
+ if (!existsSync(homePath)) {
14
+ return {
15
+ id: "agentweaver-home-01",
16
+ status: DoctorStatus.Fail,
17
+ title: "agentweaver-home",
18
+ message: `Directory does not exist: ${homePath}`,
19
+ hint: "Create the ~/.agentweaver directory or set AGENTWEAVER_HOME environment variable",
20
+ details: `resolved path: ${homePath}`,
21
+ };
22
+ }
23
+ try {
24
+ accessSync(homePath, constants.R_OK | constants.W_OK);
25
+ return {
26
+ id: "agentweaver-home-01",
27
+ status: DoctorStatus.Ok,
28
+ title: "agentweaver-home",
29
+ message: `Directory accessible and writable: ${homePath}`,
30
+ details: `resolved path: ${homePath}`,
31
+ };
32
+ }
33
+ catch {
34
+ try {
35
+ accessSync(homePath, constants.R_OK);
36
+ return {
37
+ id: "agentweaver-home-01",
38
+ status: DoctorStatus.Warn,
39
+ title: "agentweaver-home",
40
+ message: `Directory exists but is not writable: ${homePath}`,
41
+ hint: "Check directory permissions; AgentWeaver needs write access to this directory",
42
+ details: `resolved path: ${homePath}`,
43
+ };
44
+ }
45
+ catch {
46
+ return {
47
+ id: "agentweaver-home-01",
48
+ status: DoctorStatus.Fail,
49
+ title: "agentweaver-home",
50
+ message: `Directory exists but is not readable: ${homePath}`,
51
+ hint: "Check directory permissions",
52
+ details: `resolved path: ${homePath}`,
53
+ };
54
+ }
55
+ }
56
+ },
57
+ };
@@ -0,0 +1,9 @@
1
+ export const CATEGORY = {
2
+ SYSTEM: "system",
3
+ NODE_VERSION: "node-version",
4
+ AGENTWEAVER_HOME: "agentweaver-home",
5
+ CWD_CONTEXT: "cwd-context",
6
+ EXECUTORS: "executors",
7
+ ENV_DIAGNOSTICS: "env-diagnostics",
8
+ FLOW_READINESS: "flow-readiness",
9
+ };
@@ -0,0 +1,69 @@
1
+ import { accessSync, constants, existsSync } from "node:fs";
2
+ import { DoctorStatus } from "../types.js";
3
+ import { CATEGORY } from "./category.js";
4
+ const SOFT_CHECK_ID = "cwd-context-01";
5
+ export const cwdContextCheck = {
6
+ id: "cwd-context-01",
7
+ category: CATEGORY.CWD_CONTEXT,
8
+ title: "cwd-context",
9
+ dependencies: [],
10
+ execute: async () => {
11
+ const cwd = process.cwd();
12
+ let permissionStatus;
13
+ let permissionMessage;
14
+ let permissionHint;
15
+ try {
16
+ accessSync(cwd, constants.R_OK | constants.W_OK);
17
+ permissionStatus = DoctorStatus.Ok;
18
+ permissionMessage = "Working directory is readable and writable";
19
+ permissionHint = undefined;
20
+ }
21
+ catch {
22
+ try {
23
+ accessSync(cwd, constants.R_OK);
24
+ permissionStatus = DoctorStatus.Warn;
25
+ permissionMessage = "Working directory is readable but not writable";
26
+ permissionHint = "Some operations may fail if write access is required";
27
+ }
28
+ catch {
29
+ permissionStatus = DoctorStatus.Fail;
30
+ permissionMessage = "Working directory is not readable";
31
+ permissionHint = "Check directory permissions";
32
+ }
33
+ }
34
+ const gitRepoExists = existsSync(".git");
35
+ const gitStatusMessage = gitRepoExists ? "git repository detected" : "not a git repository";
36
+ const gitStatus = gitRepoExists ? DoctorStatus.Ok : DoctorStatus.Warn;
37
+ if (permissionStatus === DoctorStatus.Ok && gitStatus === DoctorStatus.Ok) {
38
+ return {
39
+ id: "cwd-context-01",
40
+ status: DoctorStatus.Ok,
41
+ title: "cwd-context",
42
+ message: `${permissionMessage}; ${gitStatusMessage}`,
43
+ details: `cwd: ${cwd}, git: ${gitStatusMessage}`,
44
+ };
45
+ }
46
+ if (permissionStatus === DoctorStatus.Ok && gitStatus === DoctorStatus.Warn) {
47
+ return {
48
+ id: "cwd-context-01",
49
+ status: DoctorStatus.Warn,
50
+ title: "cwd-context",
51
+ message: `${permissionMessage}; ${gitStatusMessage} (soft warning)`,
52
+ hint: "Git repository is recommended but not required",
53
+ details: `cwd: ${cwd}, git: ${gitStatusMessage}`,
54
+ };
55
+ }
56
+ const result = {
57
+ id: "cwd-context-01",
58
+ status: permissionStatus,
59
+ title: "cwd-context",
60
+ message: permissionMessage,
61
+ details: `cwd: ${cwd}, git: ${gitStatusMessage}`,
62
+ };
63
+ if (permissionHint) {
64
+ result.hint = permissionHint;
65
+ }
66
+ return result;
67
+ },
68
+ };
69
+ export const SOFT_CHECK_IDS = [SOFT_CHECK_ID];
@@ -0,0 +1,171 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { DoctorStatus } from "../types.js";
5
+ import { CATEGORY } from "./category.js";
6
+ const MONITORED_KEYS = [
7
+ "JIRA_API_KEY",
8
+ "JIRA_USERNAME",
9
+ "JIRA_AUTH_MODE",
10
+ "JIRA_BASE_URL",
11
+ "GITLAB_TOKEN",
12
+ "AGENTWEAVER_HOME",
13
+ "CODEX_BIN",
14
+ "CODEX_MODEL",
15
+ "OPENCODE_BIN",
16
+ "OPENCODE_MODEL",
17
+ ];
18
+ const SECRET_KEYS = new Set(["JIRA_API_KEY", "GITLAB_TOKEN"]);
19
+ const JIRA_AUTH_MODE_ALLOWED_VALUES = ["auto", "basic", "bearer"];
20
+ function maskSecret(value) {
21
+ if (value.length <= 6) {
22
+ if (value.length <= 3) {
23
+ return "***";
24
+ }
25
+ const start = value.slice(0, Math.ceil(value.length / 2));
26
+ const end = value.slice(Math.ceil(value.length / 2));
27
+ return `${start}***${end}`;
28
+ }
29
+ const start = value.slice(0, 3);
30
+ const end = value.slice(-3);
31
+ return `${start}***${end}`;
32
+ }
33
+ function globalConfigDir() {
34
+ return path.join(os.homedir(), ".agentweaver");
35
+ }
36
+ function parseEnvFileRaw(envFilePath) {
37
+ const result = {};
38
+ if (!existsSync(envFilePath)) {
39
+ return result;
40
+ }
41
+ const lines = readFileSync(envFilePath, "utf8").split(/\r?\n/);
42
+ for (const rawLine of lines) {
43
+ let line = rawLine.trim();
44
+ if (!line || line.startsWith("#")) {
45
+ continue;
46
+ }
47
+ if (line.startsWith("export ")) {
48
+ line = line.slice(7).trim();
49
+ }
50
+ const separatorIndex = line.indexOf("=");
51
+ if (separatorIndex < 0) {
52
+ continue;
53
+ }
54
+ const key = line.slice(0, separatorIndex).trim();
55
+ if (!key) {
56
+ continue;
57
+ }
58
+ let value = line.slice(separatorIndex + 1).trim();
59
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
60
+ value = value.slice(1, -1);
61
+ }
62
+ result[key] = value;
63
+ }
64
+ return result;
65
+ }
66
+ function getProjectEnvPath() {
67
+ return path.join(process.cwd(), ".agentweaver", ".env");
68
+ }
69
+ function getGlobalEnvPath() {
70
+ return path.join(globalConfigDir(), ".env");
71
+ }
72
+ function determineSource(key, shellSnapshot, currentValue) {
73
+ if (currentValue === null) {
74
+ return "missing";
75
+ }
76
+ const isInShellSnapshot = shellSnapshot.hasOwnProperty(key);
77
+ if (isInShellSnapshot) {
78
+ return "shell";
79
+ }
80
+ const globalEnv = parseEnvFileRaw(getGlobalEnvPath());
81
+ if (globalEnv.hasOwnProperty(key)) {
82
+ return "global";
83
+ }
84
+ const projectEnv = parseEnvFileRaw(getProjectEnvPath());
85
+ if (projectEnv.hasOwnProperty(key)) {
86
+ return "project-local";
87
+ }
88
+ return "shell";
89
+ }
90
+ function getDefaultValue(key) {
91
+ switch (key) {
92
+ case "AGENTWEAVER_HOME":
93
+ return path.join(os.homedir(), ".agentweaver");
94
+ default:
95
+ return null;
96
+ }
97
+ }
98
+ function validateJiraAuthMode(value) {
99
+ if (value === null) {
100
+ return true;
101
+ }
102
+ return JIRA_AUTH_MODE_ALLOWED_VALUES.includes(value);
103
+ }
104
+ function checkEnvDiagnostics() {
105
+ const shellSnapshot = {};
106
+ for (const key of Object.keys(process.env)) {
107
+ shellSnapshot[key] = process.env[key];
108
+ }
109
+ const projectEnv = parseEnvFileRaw(getProjectEnvPath());
110
+ const globalEnv = parseEnvFileRaw(getGlobalEnvPath());
111
+ const keyInfos = [];
112
+ let hasWarnings = false;
113
+ for (const key of MONITORED_KEYS) {
114
+ const currentValue = process.env[key] ?? null;
115
+ const source = determineSource(key, shellSnapshot, currentValue);
116
+ const isSecret = SECRET_KEYS.has(key);
117
+ let maskedValue = null;
118
+ if (currentValue !== null && isSecret) {
119
+ maskedValue = maskSecret(currentValue);
120
+ }
121
+ else if (currentValue !== null) {
122
+ maskedValue = currentValue;
123
+ }
124
+ const keyInfo = {
125
+ key,
126
+ source,
127
+ value: currentValue,
128
+ maskedValue,
129
+ isSecret,
130
+ };
131
+ keyInfos.push(keyInfo);
132
+ if (source === "missing") {
133
+ hasWarnings = true;
134
+ }
135
+ if (key === "JIRA_AUTH_MODE" && currentValue !== null) {
136
+ if (!validateJiraAuthMode(currentValue)) {
137
+ hasWarnings = true;
138
+ }
139
+ }
140
+ }
141
+ const status = hasWarnings ? DoctorStatus.Warn : DoctorStatus.Ok;
142
+ const keyCount = keyInfos.length;
143
+ const missingCount = keyInfos.filter(k => k.source === "missing").length;
144
+ const secretCount = keyInfos.filter(k => k.isSecret).length;
145
+ const summaryParts = [];
146
+ summaryParts.push(`${keyCount} keys checked`);
147
+ if (missingCount > 0) {
148
+ summaryParts.push(`${missingCount} missing`);
149
+ }
150
+ if (secretCount > 0) {
151
+ summaryParts.push(`${secretCount} secrets`);
152
+ }
153
+ const result = {
154
+ id: "env-diagnostics-01",
155
+ status,
156
+ title: "env-config",
157
+ message: summaryParts.join(", "),
158
+ ...(missingCount > 0 ? { hint: `${missingCount} configuration keys are missing` } : {}),
159
+ details: JSON.stringify(keyInfos),
160
+ };
161
+ return result;
162
+ }
163
+ export const envDiagnosticsCheck = {
164
+ id: "env-diagnostics-01",
165
+ category: CATEGORY.ENV_DIAGNOSTICS,
166
+ title: "env-config",
167
+ dependencies: [],
168
+ execute: async () => {
169
+ return checkEnvDiagnostics();
170
+ },
171
+ };
@@ -0,0 +1,106 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { DoctorStatus } from "../types.js";
3
+ import { CATEGORY } from "./category.js";
4
+ import { ALLOWED_MODELS_BY_EXECUTOR } from "../../pipeline/launch-profile-config.js";
5
+ import { findCmdPath, isExecutable } from "../../runtime/command-resolution.js";
6
+ function getEnvVarName(executorId) {
7
+ return executorId === "codex" ? "CODEX_BIN" : "OPENCODE_BIN";
8
+ }
9
+ function getCommandName(executorId) {
10
+ return executorId === "codex" ? "codex" : "opencode";
11
+ }
12
+ function resolveBinaryPath(executorId) {
13
+ const envVarName = getEnvVarName(executorId);
14
+ const commandName = getCommandName(executorId);
15
+ const configuredPath = process.env[envVarName];
16
+ if (configuredPath) {
17
+ if (isExecutable(configuredPath)) {
18
+ return { path: configuredPath, source: "env-override" };
19
+ }
20
+ return { path: null, source: "not-found" };
21
+ }
22
+ const foundPath = findCmdPath(commandName, "");
23
+ if (foundPath) {
24
+ return { path: foundPath, source: "PATH" };
25
+ }
26
+ return { path: null, source: "not-found" };
27
+ }
28
+ function runSmokeCheck(executorPath) {
29
+ const result = spawnSync(executorPath, ["--version"], { encoding: "utf8", stdio: "pipe" });
30
+ if (result.status === 0 && result.stdout) {
31
+ return result.stdout.trim();
32
+ }
33
+ return null;
34
+ }
35
+ function buildDetailsObj(executorId, resolution, versionOutput) {
36
+ return {
37
+ path: resolution.path,
38
+ source: resolution.source,
39
+ executable: resolution.path !== null && isExecutable(resolution.path),
40
+ versionOutput,
41
+ };
42
+ }
43
+ function createResult(executorId, status, message, hint, details, resolution, versionOutput) {
44
+ const result = {
45
+ id: `${executorId}-executor-01`,
46
+ status,
47
+ title: executorId,
48
+ message,
49
+ };
50
+ if (hint) {
51
+ result.hint = hint;
52
+ }
53
+ if (details) {
54
+ result.details = details;
55
+ }
56
+ result.detailsObj = buildDetailsObj(executorId, resolution, versionOutput);
57
+ return result;
58
+ }
59
+ function checkExecutor(executorId) {
60
+ const resolution = resolveBinaryPath(executorId);
61
+ if (resolution.path === null) {
62
+ const hint = executorId === "codex"
63
+ ? "Set CODEX_BIN environment variable to point to the codex binary"
64
+ : "Set OPENCODE_BIN environment variable to point to the opencode binary";
65
+ return createResult(executorId, DoctorStatus.Fail, `${executorId} binary not found`, hint, `source: ${resolution.source}`, resolution, null);
66
+ }
67
+ if (!isExecutable(resolution.path)) {
68
+ const hint = `Binary at ${resolution.path} is not executable`;
69
+ return createResult(executorId, DoctorStatus.Fail, `${executorId} binary is not executable`, hint, `path: ${resolution.path}`, resolution, null);
70
+ }
71
+ const versionOutput = runSmokeCheck(resolution.path);
72
+ if (versionOutput === null) {
73
+ return createResult(executorId, DoctorStatus.Fail, `${executorId} --version check failed`, `${executorId} --version did not produce expected output`, `path: ${resolution.path}, source: ${resolution.source}`, resolution, null);
74
+ }
75
+ const allowedModels = ALLOWED_MODELS_BY_EXECUTOR[executorId];
76
+ const modelWarnings = [];
77
+ for (const model of allowedModels) {
78
+ const modelResult = spawnSync(resolution.path, ["--model", model, "--version"], { encoding: "utf8", stdio: "pipe" });
79
+ if (modelResult.status !== 0) {
80
+ modelWarnings.push(`Model '${model}' validation failed (exit code ${modelResult.status})`);
81
+ }
82
+ }
83
+ const message = versionOutput;
84
+ if (modelWarnings.length > 0) {
85
+ return createResult(executorId, DoctorStatus.Warn, message, `Some models failed validation: ${modelWarnings.join("; ")}`, `source: ${resolution.source}, models validated: ${allowedModels.join(", ")}`, resolution, versionOutput);
86
+ }
87
+ return createResult(executorId, DoctorStatus.Ok, message, undefined, `source: ${resolution.source}`, resolution, versionOutput);
88
+ }
89
+ export const codexExecutorCheck = {
90
+ id: "codex-executor-01",
91
+ category: CATEGORY.EXECUTORS,
92
+ title: "codex",
93
+ dependencies: [],
94
+ execute: async () => {
95
+ return checkExecutor("codex");
96
+ },
97
+ };
98
+ export const opencodeExecutorCheck = {
99
+ id: "opencode-executor-01",
100
+ category: CATEGORY.EXECUTORS,
101
+ title: "opencode",
102
+ dependencies: [],
103
+ execute: async () => {
104
+ return checkExecutor("opencode");
105
+ },
106
+ };