agentweaver 0.1.6 → 0.1.7

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.
@@ -0,0 +1,155 @@
1
+ {
2
+ "kind": "run-go-tests-loop-flow",
3
+ "version": 1,
4
+ "phases": [
5
+ {
6
+ "id": "run_go_tests_try_1",
7
+ "steps": [
8
+ {
9
+ "id": "run_go_tests",
10
+ "node": "local-script-check",
11
+ "params": {
12
+ "argv": {
13
+ "list": [
14
+ { "ref": "params.runGoTestsScript" }
15
+ ]
16
+ },
17
+ "labelText": {
18
+ "const": "Running run_go_tests.sh locally (attempt 1)"
19
+ }
20
+ },
21
+ "stopFlowIf": {
22
+ "equals": [
23
+ { "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.ok" },
24
+ { "const": true }
25
+ ]
26
+ }
27
+ },
28
+ {
29
+ "id": "fix_go_tests",
30
+ "when": {
31
+ "equals": [
32
+ { "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.ok" },
33
+ { "const": false }
34
+ ]
35
+ },
36
+ "node": "codex-local-prompt",
37
+ "prompt": {
38
+ "templateRef": "run-go-tests-loop-fix",
39
+ "extraPrompt": {
40
+ "appendPrompt": {
41
+ "base": { "ref": "params.extraPrompt" },
42
+ "suffix": {
43
+ "template": "Последний результат run_go_tests.sh: exitCode={exit_code}, summary={summary}. Исправь только то, что мешает успешному прохождению проверки.",
44
+ "vars": {
45
+ "exit_code": { "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.exitCode" },
46
+ "summary": { "ref": "steps.run_go_tests_try_1.run_go_tests.outputs.parsed.summary" }
47
+ }
48
+ }
49
+ }
50
+ },
51
+ "format": "task-prompt"
52
+ },
53
+ "params": {
54
+ "labelText": {
55
+ "const": "Running Codex Go tests loop fix (attempt 1)"
56
+ },
57
+ "model": { "const": "gpt-5.4" }
58
+ }
59
+ }
60
+ ]
61
+ },
62
+ {
63
+ "repeat": {
64
+ "var": "attempt",
65
+ "from": 2,
66
+ "to": 5
67
+ },
68
+ "phases": [
69
+ {
70
+ "id": "run_go_tests_try_${attempt}",
71
+ "when": {
72
+ "equals": [
73
+ { "ref": "steps.run_go_tests_try_${attempt_minus_one}.run_go_tests.outputs.parsed.ok" },
74
+ { "const": false }
75
+ ]
76
+ },
77
+ "steps": [
78
+ {
79
+ "id": "run_go_tests",
80
+ "node": "local-script-check",
81
+ "params": {
82
+ "argv": {
83
+ "list": [
84
+ { "ref": "params.runGoTestsScript" }
85
+ ]
86
+ },
87
+ "labelText": {
88
+ "template": "Running run_go_tests.sh locally (attempt ${attempt})"
89
+ }
90
+ },
91
+ "stopFlowIf": {
92
+ "equals": [
93
+ { "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.ok" },
94
+ { "const": true }
95
+ ]
96
+ }
97
+ },
98
+ {
99
+ "id": "fix_go_tests",
100
+ "when": {
101
+ "equals": [
102
+ { "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.ok" },
103
+ { "const": false }
104
+ ]
105
+ },
106
+ "node": "codex-local-prompt",
107
+ "prompt": {
108
+ "templateRef": "run-go-tests-loop-fix",
109
+ "extraPrompt": {
110
+ "appendPrompt": {
111
+ "base": { "ref": "params.extraPrompt" },
112
+ "suffix": {
113
+ "template": "Последний результат run_go_tests.sh: exitCode={exit_code}, summary={summary}. Исправь только то, что мешает успешному прохождению проверки.",
114
+ "vars": {
115
+ "exit_code": { "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.exitCode" },
116
+ "summary": { "ref": "steps.run_go_tests_try_${attempt}.run_go_tests.outputs.parsed.summary" }
117
+ }
118
+ }
119
+ }
120
+ },
121
+ "format": "task-prompt"
122
+ },
123
+ "params": {
124
+ "labelText": {
125
+ "template": "Running Codex Go tests loop fix (attempt ${attempt})"
126
+ },
127
+ "model": { "const": "gpt-5.4" }
128
+ }
129
+ }
130
+ ]
131
+ }
132
+ ]
133
+ },
134
+ {
135
+ "id": "run_go_tests_failed",
136
+ "steps": [
137
+ {
138
+ "id": "assert_run_go_tests_success",
139
+ "node": "file-check",
140
+ "params": {
141
+ "path": { "ref": "params.runGoTestsScript" }
142
+ },
143
+ "expect": [
144
+ {
145
+ "kind": "step-output",
146
+ "value": { "ref": "steps.run_go_tests_try_5.run_go_tests.outputs.parsed.ok" },
147
+ "equals": { "const": true },
148
+ "message": "run-go-tests-loop exhausted all attempts without a successful run_go_tests.sh execution."
149
+ }
150
+ ]
151
+ }
152
+ ]
153
+ }
154
+ ]
155
+ }
@@ -5,6 +5,31 @@
5
5
  {
6
6
  "id": "task_describe",
7
7
  "steps": [
8
+ {
9
+ "id": "fetch_jira",
10
+ "node": "jira-fetch",
11
+ "params": {
12
+ "jiraApiUrl": { "ref": "params.jiraApiUrl" },
13
+ "outputFile": {
14
+ "artifact": {
15
+ "kind": "jira-task-file",
16
+ "taskKey": { "ref": "params.taskKey" }
17
+ }
18
+ }
19
+ },
20
+ "expect": [
21
+ {
22
+ "kind": "require-file",
23
+ "path": {
24
+ "artifact": {
25
+ "kind": "jira-task-file",
26
+ "taskKey": { "ref": "params.taskKey" }
27
+ }
28
+ },
29
+ "message": "Jira fetch node did not produce the Jira task file."
30
+ }
31
+ ]
32
+ },
8
33
  {
9
34
  "id": "run_codex_task_describe",
10
35
  "node": "codex-local-prompt",
@@ -8,6 +8,7 @@ import { fileCheckNode } from "./nodes/file-check-node.js";
8
8
  import { flowRunNode } from "./nodes/flow-run-node.js";
9
9
  import { gitlabReviewArtifactsNode } from "./nodes/gitlab-review-artifacts-node.js";
10
10
  import { jiraFetchNode } from "./nodes/jira-fetch-node.js";
11
+ import { jiraIssueCheckNode } from "./nodes/jira-issue-check-node.js";
11
12
  import { localScriptCheckNode } from "./nodes/local-script-check-node.js";
12
13
  import { planCodexNode } from "./nodes/plan-codex-node.js";
13
14
  import { reviewClaudeNode } from "./nodes/review-claude-node.js";
@@ -27,6 +28,7 @@ const builtInNodes = {
27
28
  "flow-run": flowRunNode,
28
29
  "gitlab-review-artifacts": gitlabReviewArtifactsNode,
29
30
  "jira-fetch": jiraFetchNode,
31
+ "jira-issue-check": jiraIssueCheckNode,
30
32
  "local-script-check": localScriptCheckNode,
31
33
  "plan-codex": planCodexNode,
32
34
  "review-claude": reviewClaudeNode,
@@ -62,6 +64,12 @@ const builtInNodeMetadata = {
62
64
  requiredParams: ["gitlabReviewJsonFile", "reviewFile", "reviewJsonFile"],
63
65
  },
64
66
  "jira-fetch": { kind: "jira-fetch", version: 1, prompt: "forbidden", requiredParams: ["jiraApiUrl", "outputFile"] },
67
+ "jira-issue-check": {
68
+ kind: "jira-issue-check",
69
+ version: 1,
70
+ prompt: "forbidden",
71
+ requiredParams: ["jiraTaskFile", "allowedIssueTypes"],
72
+ },
65
73
  "local-script-check": { kind: "local-script-check", version: 1, prompt: "forbidden", requiredParams: ["argv", "labelText"] },
66
74
  "plan-codex": { kind: "plan-codex", version: 1, prompt: "forbidden", requiredParams: ["prompt", "requiredArtifacts"] },
67
75
  "review-claude": {
@@ -0,0 +1,53 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { TaskRunnerError } from "../../errors.js";
3
+ import { printInfo } from "../../tui.js";
4
+ function extractIssueTypeName(path) {
5
+ let parsed;
6
+ try {
7
+ parsed = JSON.parse(readFileSync(path, "utf8"));
8
+ }
9
+ catch (error) {
10
+ throw new TaskRunnerError(`Failed to parse Jira issue JSON ${path}: ${error.message}`);
11
+ }
12
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
13
+ throw new TaskRunnerError(`Jira issue payload in ${path} must be a JSON object.`);
14
+ }
15
+ const fields = parsed.fields;
16
+ if (!fields || typeof fields !== "object" || Array.isArray(fields)) {
17
+ throw new TaskRunnerError(`Jira issue payload in ${path} does not contain 'fields'.`);
18
+ }
19
+ const issueType = fields.issuetype;
20
+ if (!issueType || typeof issueType !== "object" || Array.isArray(issueType)) {
21
+ throw new TaskRunnerError(`Jira issue payload in ${path} does not contain 'fields.issuetype'.`);
22
+ }
23
+ const issueTypeName = issueType.name;
24
+ if (typeof issueTypeName !== "string" || issueTypeName.trim().length === 0) {
25
+ throw new TaskRunnerError(`Jira issue payload in ${path} does not contain 'fields.issuetype.name'.`);
26
+ }
27
+ return issueTypeName.trim();
28
+ }
29
+ export const jiraIssueCheckNode = {
30
+ kind: "jira-issue-check",
31
+ version: 1,
32
+ async run(_context, params) {
33
+ if (params.labelText) {
34
+ printInfo(params.labelText);
35
+ }
36
+ const issueType = extractIssueTypeName(params.jiraTaskFile);
37
+ const normalizedIssueType = issueType.toLowerCase();
38
+ const allowedIssueTypes = params.allowedIssueTypes
39
+ .map((candidate) => candidate.trim())
40
+ .filter((candidate) => candidate.length > 0);
41
+ if (allowedIssueTypes.length === 0) {
42
+ throw new TaskRunnerError("jira-issue-check requires at least one allowed issue type.");
43
+ }
44
+ const isAllowed = allowedIssueTypes.some((candidate) => candidate.toLowerCase() === normalizedIssueType);
45
+ if (!isAllowed) {
46
+ throw new TaskRunnerError(`Flow 'bug-analyze' supports only Jira issue types: ${allowedIssueTypes.join(", ")}. ` +
47
+ `Fetched issue type: ${issueType}.`);
48
+ }
49
+ return {
50
+ value: { issueType },
51
+ };
52
+ },
53
+ };
@@ -1,4 +1,4 @@
1
- import { BUG_ANALYZE_PROMPT_TEMPLATE, BUG_FIX_PROMPT_TEMPLATE, IMPLEMENT_PROMPT_TEMPLATE, MR_DESCRIPTION_PROMPT_TEMPLATE, PLAN_PROMPT_TEMPLATE, REVIEW_FIX_PROMPT_TEMPLATE, REVIEW_PROMPT_TEMPLATE, REVIEW_REPLY_PROMPT_TEMPLATE, REVIEW_REPLY_SUMMARY_PROMPT_TEMPLATE, REVIEW_SUMMARY_PROMPT_TEMPLATE, RUN_LINTER_LOOP_FIX_PROMPT_TEMPLATE, RUN_TESTS_LOOP_FIX_PROMPT_TEMPLATE, TASK_SUMMARY_PROMPT_TEMPLATE, } from "../prompts.js";
1
+ import { BUG_ANALYZE_PROMPT_TEMPLATE, BUG_FIX_PROMPT_TEMPLATE, IMPLEMENT_PROMPT_TEMPLATE, MR_DESCRIPTION_PROMPT_TEMPLATE, PLAN_PROMPT_TEMPLATE, REVIEW_FIX_PROMPT_TEMPLATE, REVIEW_PROJECT_PROMPT_TEMPLATE, REVIEW_PROMPT_TEMPLATE, REVIEW_REPLY_PROJECT_PROMPT_TEMPLATE, REVIEW_REPLY_PROMPT_TEMPLATE, REVIEW_REPLY_SUMMARY_PROMPT_TEMPLATE, REVIEW_SUMMARY_PROMPT_TEMPLATE, RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE, RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE, TASK_SUMMARY_PROMPT_TEMPLATE, } from "../prompts.js";
2
2
  const promptTemplates = {
3
3
  "bug-analyze": BUG_ANALYZE_PROMPT_TEMPLATE,
4
4
  "bug-fix": BUG_FIX_PROMPT_TEMPLATE,
@@ -6,12 +6,14 @@ const promptTemplates = {
6
6
  "mr-description": MR_DESCRIPTION_PROMPT_TEMPLATE,
7
7
  plan: PLAN_PROMPT_TEMPLATE,
8
8
  review: REVIEW_PROMPT_TEMPLATE,
9
+ "review-project": REVIEW_PROJECT_PROMPT_TEMPLATE,
9
10
  "review-fix": REVIEW_FIX_PROMPT_TEMPLATE,
10
11
  "review-reply": REVIEW_REPLY_PROMPT_TEMPLATE,
12
+ "review-reply-project": REVIEW_REPLY_PROJECT_PROMPT_TEMPLATE,
11
13
  "review-reply-summary": REVIEW_REPLY_SUMMARY_PROMPT_TEMPLATE,
12
14
  "review-summary": REVIEW_SUMMARY_PROMPT_TEMPLATE,
13
- "run-linter-loop-fix": RUN_LINTER_LOOP_FIX_PROMPT_TEMPLATE,
14
- "run-tests-loop-fix": RUN_TESTS_LOOP_FIX_PROMPT_TEMPLATE,
15
+ "run-go-linter-loop-fix": RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE,
16
+ "run-go-tests-loop-fix": RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE,
15
17
  "task-summary": TASK_SUMMARY_PROMPT_TEMPLATE,
16
18
  };
17
19
  export function isPromptTemplateRef(value) {
package/dist/prompts.js CHANGED
@@ -37,10 +37,19 @@ export const REVIEW_PROMPT_TEMPLATE = "Проведи код-ревью теку
37
37
  "Сначала запиши структурированный результат в {review_json_file} в виде объекта { summary: string, ready_to_merge: boolean, findings: [{ severity: string, title: string, description: string }] }. " +
38
38
  "Затем запиши производную markdown-версию в {review_file}. " +
39
39
  "Если ready_to_merge=true и нет блокеров, препятствующих merge - создай файл ready-to-merge.md.";
40
+ export const REVIEW_PROJECT_PROMPT_TEMPLATE = "Проведи код-ревью текущих изменений в проекте без Jira-контекста. " +
41
+ "Оцени качество изменений по текущему коду, тестам, рискам регрессий и общему инженерному качеству. " +
42
+ "Сначала запиши структурированный результат в {review_json_file} в виде объекта { summary: string, ready_to_merge: boolean, findings: [{ severity: string, title: string, description: string }] }. " +
43
+ "Затем запиши производную markdown-версию в {review_file}. " +
44
+ "Если ready_to_merge=true и нет блокеров, создай файл {ready_to_merge_file}.";
40
45
  export const REVIEW_REPLY_PROMPT_TEMPLATE = "Твой коллега провёл код-ревью и записал структурированный результат в {review_json_file}. " +
41
46
  "Используй только структурированные артефакты как source of truth: задачу в {jira_task_file}, дизайн в {design_json_file}, план в {plan_json_file} и review в {review_json_file}. " +
42
47
  "Сначала запиши структурированный ответ в {review_reply_json_file} в виде объекта { summary: string, ready_to_merge: boolean, responses: [{ finding_title: string, disposition: string, action: string }] }. " +
43
48
  "Затем запиши производную markdown-версию в {review_reply_file}.";
49
+ export const REVIEW_REPLY_PROJECT_PROMPT_TEMPLATE = "Твой коллега провёл код-ревью и записал структурированный результат в {review_json_file}. " +
50
+ "Используй review в {review_json_file} как source of truth, разберись в замечаниях и подготовь структурированный ответ. " +
51
+ "Сначала запиши структурированный ответ в {review_reply_json_file} в виде объекта { summary: string, ready_to_merge: boolean, responses: [{ finding_title: string, disposition: string, action: string }] }. " +
52
+ "Затем запиши производную markdown-версию в {review_reply_file}.";
44
53
  export const REVIEW_SUMMARY_PROMPT_TEMPLATE = "Посмотри в {review_file}. " +
45
54
  "Сделай краткий список комментариев без подробностей, 3-7 пунктов. " +
46
55
  "Запиши результат в {review_summary_file}.";
@@ -56,8 +65,8 @@ export const REVIEW_FIX_PROMPT_TEMPLATE = "Используй только ст
56
65
  export const TASK_SUMMARY_PROMPT_TEMPLATE = "Посмотри в {jira_task_file}. " +
57
66
  "Сделай краткое резюме задачи, на 1-2 абзаца. " +
58
67
  "Сначала запиши source-of-truth JSON в {task_summary_json_file} в виде объекта { summary: string }, затем markdown-версию в {task_summary_file}.";
59
- export const RUN_TESTS_LOOP_FIX_PROMPT_TEMPLATE = "Запусти ./run_tests.sh, проанализируй последнюю ошибку проверки, исправь код и подготовь изменения так, чтобы следующий прогон run_tests.sh прошёл успешно.";
60
- export const RUN_LINTER_LOOP_FIX_PROMPT_TEMPLATE = "Запусти ./run_linter.sh, проанализируй последнюю ошибку линтера или генерации, исправь код и подготовь изменения так, чтобы следующий прогон run_linter.sh прошёл успешно.";
68
+ export const RUN_GO_TESTS_LOOP_FIX_PROMPT_TEMPLATE = "Запусти ./run_go_tests.sh, проанализируй последнюю ошибку проверки, исправь код и подготовь изменения так, чтобы следующий прогон run_go_tests.sh прошёл успешно.";
69
+ export const RUN_GO_LINTER_LOOP_FIX_PROMPT_TEMPLATE = "Запусти ./run_go_linter.sh, проанализируй последнюю ошибку линтера или генерации, исправь код и подготовь изменения так, чтобы следующий прогон run_go_linter.sh прошёл успешно.";
61
70
  export const AUTO_REVIEW_FIX_EXTRA_PROMPT = "Исправлять только блокеры, критикалы и важные";
62
71
  export function formatTemplate(template, values) {
63
72
  let result = template;
package/dist/scope.js ADDED
@@ -0,0 +1,118 @@
1
+ import crypto from "node:crypto";
2
+ import process from "node:process";
3
+ import { execFileSync } from "node:child_process";
4
+ import { ensureScopeWorkspaceDir, jiraTaskFile } from "./artifacts.js";
5
+ import { TaskRunnerError } from "./errors.js";
6
+ import { buildJiraApiUrl, buildJiraBrowseUrl, extractIssueKey } from "./jira.js";
7
+ function gitOutput(args) {
8
+ try {
9
+ const output = execFileSync("git", args, {
10
+ cwd: process.cwd(),
11
+ encoding: "utf8",
12
+ stdio: ["ignore", "pipe", "ignore"],
13
+ });
14
+ const trimmed = output.trim();
15
+ return trimmed.length > 0 ? trimmed : null;
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ function shortHash(input) {
22
+ return crypto.createHash("sha1").update(input).digest("hex").slice(0, 8);
23
+ }
24
+ export function sanitizeScopeName(value) {
25
+ const normalized = value
26
+ .trim()
27
+ .toLowerCase()
28
+ .replaceAll(/[^a-z0-9._@-]+/g, "-")
29
+ .replaceAll(/-+/g, "-")
30
+ .replaceAll(/^-|-$/g, "");
31
+ if (!normalized) {
32
+ throw new TaskRunnerError("Scope name is empty after sanitization. Use letters, digits, '.', '_', '-' or '@'.");
33
+ }
34
+ return normalized;
35
+ }
36
+ export function detectGitBranchName() {
37
+ const branchName = gitOutput(["rev-parse", "--abbrev-ref", "HEAD"]);
38
+ if (!branchName) {
39
+ return null;
40
+ }
41
+ if (branchName === "HEAD") {
42
+ return null;
43
+ }
44
+ return branchName;
45
+ }
46
+ export function detectProjectRoot() {
47
+ return gitOutput(["rev-parse", "--show-toplevel"]) ?? process.cwd();
48
+ }
49
+ export function buildProjectScopeKey(explicitScope) {
50
+ const projectRoot = detectProjectRoot();
51
+ const worktreeHash = shortHash(projectRoot);
52
+ if (explicitScope?.trim()) {
53
+ return {
54
+ scopeKey: sanitizeScopeName(explicitScope),
55
+ gitBranchName: detectGitBranchName(),
56
+ worktreeHash,
57
+ projectRoot,
58
+ };
59
+ }
60
+ const branchName = detectGitBranchName();
61
+ const branchSlug = sanitizeScopeName(branchName ?? "detached-head");
62
+ return {
63
+ scopeKey: `${branchSlug}@${worktreeHash}`,
64
+ gitBranchName: branchName,
65
+ worktreeHash,
66
+ projectRoot,
67
+ };
68
+ }
69
+ export function resolveTaskScope(jiraRef, explicitScope) {
70
+ const jiraIssueKey = extractIssueKey(jiraRef);
71
+ const scopeKey = explicitScope?.trim() ? sanitizeScopeName(explicitScope) : jiraIssueKey;
72
+ ensureScopeWorkspaceDir(scopeKey);
73
+ return {
74
+ scopeType: "task",
75
+ scopeKey,
76
+ jiraRef,
77
+ jiraIssueKey,
78
+ jiraBrowseUrl: buildJiraBrowseUrl(jiraRef),
79
+ jiraApiUrl: buildJiraApiUrl(jiraRef),
80
+ jiraTaskFile: jiraTaskFile(scopeKey),
81
+ };
82
+ }
83
+ export function resolveProjectScope(explicitScope) {
84
+ const { scopeKey, gitBranchName, worktreeHash, projectRoot } = buildProjectScopeKey(explicitScope);
85
+ ensureScopeWorkspaceDir(scopeKey);
86
+ return {
87
+ scopeType: "project",
88
+ scopeKey,
89
+ gitBranchName,
90
+ worktreeHash,
91
+ projectRoot,
92
+ };
93
+ }
94
+ export function buildJiraTaskInputForm() {
95
+ return {
96
+ formId: "jira-task-input",
97
+ title: "Jira Task",
98
+ description: "Укажи Jira issue key или browse URL для task-driven flow.",
99
+ submitLabel: "Continue",
100
+ fields: [
101
+ {
102
+ id: "jira_ref",
103
+ type: "text",
104
+ label: "Jira issue key or browse URL",
105
+ help: "Например: DEMO-3288 или https://jira.example.ru/browse/DEMO-3288",
106
+ required: true,
107
+ },
108
+ ],
109
+ };
110
+ }
111
+ export async function requestTaskScope(requestUserInput) {
112
+ const result = await requestUserInput(buildJiraTaskInputForm());
113
+ const jiraRef = String(result.values.jira_ref ?? "").trim();
114
+ if (!jiraRef) {
115
+ throw new TaskRunnerError("Jira issue key or browse URL is required.");
116
+ }
117
+ return resolveTaskScope(jiraRef);
118
+ }
@@ -209,7 +209,7 @@ services:
209
209
  - /tmp:exec,mode=1777
210
210
  - /root
211
211
 
212
- run-tests:
212
+ run-go-tests:
213
213
  build:
214
214
  context: .
215
215
  dockerfile: Dockerfile.codex
@@ -260,7 +260,7 @@ services:
260
260
  read_only: true
261
261
  bind:
262
262
  create_host_path: false
263
- entrypoint: ["/usr/local/bin/run_tests.sh"]
263
+ entrypoint: ["/usr/local/bin/run_go_tests.sh"]
264
264
  cap_drop:
265
265
  - ALL
266
266
  security_opt:
@@ -270,7 +270,7 @@ services:
270
270
  - /tmp:exec,mode=1777
271
271
  - /root
272
272
 
273
- run-linter:
273
+ run-go-linter:
274
274
  build:
275
275
  context: .
276
276
  dockerfile: Dockerfile.codex
@@ -321,7 +321,68 @@ services:
321
321
  read_only: true
322
322
  bind:
323
323
  create_host_path: false
324
- entrypoint: ["/usr/local/bin/run_linter.sh"]
324
+ entrypoint: ["/usr/local/bin/run_go_linter.sh"]
325
+ cap_drop:
326
+ - ALL
327
+ security_opt:
328
+ - no-new-privileges:true
329
+ read_only: true
330
+ tmpfs:
331
+ - /tmp:exec,mode=1777
332
+ - /root
333
+
334
+ run-go-coverage:
335
+ build:
336
+ context: .
337
+ dockerfile: Dockerfile.codex
338
+ working_dir: /workspace
339
+ init: true
340
+ user: "${LOCAL_UID:-1000}:${LOCAL_GID:-1000}"
341
+ environment:
342
+ PATH: /usr/local/go/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/codex-home/go/bin:/go/bin
343
+ CODEX_HOME: /codex-home
344
+ HOME: /codex-home/home
345
+ XDG_CACHE_HOME: /codex-home/cache/xdg
346
+ GOPATH: /codex-home/go
347
+ GOBIN: /codex-home/go/bin
348
+ GOCACHE: /codex-home/cache/go-build
349
+ GOMODCACHE: /codex-home/cache/gomod
350
+ GOLANGCI_LINT_CACHE: /codex-home/cache/golangci-lint
351
+ GOPRIVATE: ${GOPRIVATE:-gitlab.yourdomain.org/*}
352
+ GONOSUMDB: ${GONOSUMDB:-gitlab.yourdomain.org/*}
353
+ GONOPROXY: ${GONOPROXY:-gitlab.yourdomain.org/*}
354
+ GIT_ALLOW_PROTOCOL: ${GIT_ALLOW_PROTOCOL:-file:https:ssh}
355
+ GIT_TERMINAL_PROMPT: "0"
356
+ DOCKER_HOST: tcp://dockerd:2375
357
+ TESTCONTAINERS_HOST_OVERRIDE: dockerd
358
+ VERIFY_BUILD_ROOT_DIR: /workspace
359
+ depends_on:
360
+ dockerd:
361
+ condition: service_healthy
362
+ volumes:
363
+ - type: bind
364
+ source: ${PROJECT_DIR:-./}
365
+ target: /workspace
366
+ bind:
367
+ create_host_path: false
368
+ - type: bind
369
+ source: ${CODEX_HOME_DIR:-~/.codex}
370
+ target: /codex-home
371
+ bind:
372
+ create_host_path: false
373
+ - type: bind
374
+ source: ${HOST_SSH_DIR:-~/.ssh}
375
+ target: /codex-home/home/.ssh
376
+ read_only: true
377
+ bind:
378
+ create_host_path: false
379
+ - type: bind
380
+ source: ${HOST_GITCONFIG:-~/.gitconfig}
381
+ target: /codex-home/home/.gitconfig
382
+ read_only: true
383
+ bind:
384
+ create_host_path: false
385
+ entrypoint: ["/usr/local/bin/run_go_coverage.sh"]
325
386
  cap_drop:
326
387
  - ALL
327
388
  security_opt:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentweaver",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "CLI orchestrator for Jira/Codex/Claude engineering workflows",
5
5
  "keywords": [
6
6
  "agent",
@@ -32,8 +32,9 @@
32
32
  "docker-compose.yml",
33
33
  "Dockerfile.codex",
34
34
  "verify_build.sh",
35
- "run_tests.sh",
36
- "run_linter.sh"
35
+ "run_go_tests.sh",
36
+ "run_go_linter.sh",
37
+ "run_go_coverage.sh"
37
38
  ],
38
39
  "publishConfig": {
39
40
  "access": "public"
@@ -69,7 +69,7 @@ fail() {
69
69
  local command="$3"
70
70
  local details_json="${4:-{}}"
71
71
 
72
- emit_result false "tests" "run_tests" "$exit_code" "$summary" "$command" "$details_json"
72
+ emit_result false "coverage" "run_go_coverage" "$exit_code" "$summary" "$command" "$details_json"
73
73
  exit "$exit_code"
74
74
  }
75
75
 
@@ -92,9 +92,9 @@ if [[ -z "$PKGS" ]]; then
92
92
  fail 2 "Coverage package list is empty" "go list ./..." '{"failedStep":"go-list","reason":"no-test-packages"}'
93
93
  fi
94
94
 
95
- log "==> Running unit tests with coverage (go test -coverprofile)"
95
+ log "==> Running coverage check (go test -coverprofile)"
96
96
  if ! go test -coverpkg="$PKGS" -coverprofile="$COVER_FILE" -count=1 ./... >&2; then
97
- fail 1 "go test failed" "go test -coverpkg=<pkgs> -coverprofile=<file> -count=1 ./..." "$(details_json --arg failedStep "go-test" --arg coverFile "$COVER_FILE" '{failedStep: $failedStep, coverFile: $coverFile}')"
97
+ fail 1 "go test for coverage failed" "go test -coverpkg=<pkgs> -coverprofile=<file> -count=1 ./..." "$(details_json --arg failedStep "go-test" --arg coverFile "$COVER_FILE" '{failedStep: $failedStep, coverFile: $coverFile}')"
98
98
  fi
99
99
 
100
100
  log "==> Calculating coverage summary"
@@ -110,4 +110,4 @@ if ! awk -v c="$coverage" -v min="$MIN_COVERAGE" 'BEGIN {exit (c >= min ? 0 : 1)
110
110
  fail 3 "Coverage ${coverage}% is below required ${MIN_COVERAGE}%" "go test -coverprofile && go tool cover -func" "$(details_json --argjson coverage "$coverage" --argjson minCoverage "$MIN_COVERAGE" --arg failedStep "coverage-threshold" --arg coverFile "$COVER_FILE" '{coverage: $coverage, minCoverage: $minCoverage, failedStep: $failedStep, coverFile: $coverFile}')"
111
111
  fi
112
112
 
113
- emit_result true "tests" "run_tests" 0 "Tests passed with sufficient coverage" "go test -coverpkg=<pkgs> -coverprofile=<file> -count=1 ./..." "$(details_json --argjson coverage "$coverage" --argjson minCoverage "$MIN_COVERAGE" --arg coverFile "$COVER_FILE" '{coverage: $coverage, minCoverage: $minCoverage, coverFile: $coverFile}')"
113
+ emit_result true "coverage" "run_go_coverage" 0 "Coverage passed" "go test -coverpkg=<pkgs> -coverprofile=<file> -count=1 ./..." "$(details_json --argjson coverage "$coverage" --argjson minCoverage "$MIN_COVERAGE" --arg coverFile "$COVER_FILE" '{coverage: $coverage, minCoverage: $minCoverage, coverFile: $coverFile}')"
@@ -62,7 +62,7 @@ fail() {
62
62
  local command="$3"
63
63
  local details_json="${4:-{}}"
64
64
 
65
- emit_result false "linter" "run_linter" "$exit_code" "$summary" "$command" "$details_json"
65
+ emit_result false "linter" "run_go_linter" "$exit_code" "$summary" "$command" "$details_json"
66
66
  exit "$exit_code"
67
67
  }
68
68
 
@@ -86,4 +86,4 @@ if ! golangci-lint run >&2; then
86
86
  fail 1 "golangci-lint failed" "golangci-lint run" '{"failedStep":"golangci-lint"}'
87
87
  fi
88
88
 
89
- emit_result true "linter" "run_linter" 0 "Linter checks passed" "go generate ./... && golangci-lint run" "$(details_json '{steps:["go-generate","golangci-lint"]}')"
89
+ emit_result true "linter" "run_go_linter" 0 "Linter checks passed" "go generate ./... && golangci-lint run" "$(details_json '{steps:["go-generate","golangci-lint"]}')"