@agentteams/runner 0.0.62 → 0.0.63-dev.124

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.
@@ -6,7 +6,8 @@ const HARNESS_YML_PATH = ".agentteams/harness.yml";
6
6
  const EMPTY_CONFIG = {
7
7
  preHooks: [],
8
8
  postHooks: [],
9
- qualityGate: null
9
+ qualityGate: null,
10
+ conventionIds: []
10
11
  };
11
12
  /**
12
13
  * Load local harness.yml from the project's authPath.
@@ -67,7 +68,8 @@ export const mergeHarnessConfig = (local, server) => {
67
68
  postHooks: local.postHooks ?? server.postHooks ?? [],
68
69
  qualityGate: local.qualityGate !== undefined
69
70
  ? local.qualityGate
70
- : server.qualityGate ?? null
71
+ : server.qualityGate ?? null,
72
+ conventionIds: local.conventionIds ?? server.conventionIds ?? []
71
73
  };
72
74
  };
73
75
  /**
@@ -80,13 +82,43 @@ export const loadHarnessConfig = async (authPath, client, projectId) => {
80
82
  ]);
81
83
  return mergeHarnessConfig(local, server);
82
84
  };
85
+ /**
86
+ * Load harness config by specific harnessConfigId.
87
+ * Falls back to local harness.yml merge with server config.
88
+ */
89
+ export const loadHarnessConfigById = async (authPath, client, harnessConfigId) => {
90
+ const [local, server] = await Promise.all([
91
+ loadLocalHarnessConfig(authPath),
92
+ fetchServerHarnessConfigById(client, harnessConfigId)
93
+ ]);
94
+ return mergeHarnessConfig(local, server);
95
+ };
96
+ /**
97
+ * Fetch server-side harness config by its id.
98
+ */
99
+ const fetchServerHarnessConfigById = async (client, harnessConfigId) => {
100
+ try {
101
+ const response = await client.fetchHarnessConfigById(harnessConfigId);
102
+ if (!response)
103
+ return null;
104
+ return response.config;
105
+ }
106
+ catch (error) {
107
+ logger.warn("Failed to fetch server harness config by id, continuing without it", {
108
+ harnessConfigId,
109
+ error: error instanceof Error ? error.message : String(error)
110
+ });
111
+ return null;
112
+ }
113
+ };
83
114
  // ---------------------------------------------------------------------------
84
115
  // Helpers
85
116
  // ---------------------------------------------------------------------------
86
117
  const toHarnessConfig = (yml) => ({
87
118
  preHooks: yml.preHooks ?? [],
88
119
  postHooks: yml.postHooks ?? [],
89
- qualityGate: yml.qualityGate ?? null
120
+ qualityGate: yml.qualityGate ?? null,
121
+ conventionIds: yml.conventionIds ?? []
90
122
  });
91
123
  const isFileNotFoundError = (error) => {
92
124
  return (error instanceof Error &&
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/harness/config-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-loader.js","sourceRoot":"","sources":["../../src/harness/config-loader.ts"],"names":[],"mappings":"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"}
@@ -22,18 +22,21 @@ describe("mergeHarnessConfig", () => {
22
22
  assert.deepStrictEqual(result, {
23
23
  preHooks: [],
24
24
  postHooks: [],
25
- qualityGate: null
25
+ qualityGate: null,
26
+ conventionIds: []
26
27
  });
27
28
  });
28
29
  test("returns server config when local is null", () => {
29
30
  const server = {
30
31
  preHooks: [{ name: "lint", command: "npm run lint", onFailure: "fail" }],
31
32
  postHooks: [],
32
- qualityGate: { minScore: 80, onBelowThreshold: "warn" }
33
+ qualityGate: { minScore: 80, onBelowThreshold: "warn" },
34
+ conventionIds: ["conv-1"]
33
35
  };
34
36
  const result = mergeHarnessConfig(null, server);
35
37
  assert.deepStrictEqual(result.preHooks, server.preHooks);
36
38
  assert.deepStrictEqual(result.qualityGate, server.qualityGate);
39
+ assert.deepStrictEqual(result.conventionIds, ["conv-1"]);
37
40
  });
38
41
  test("returns local config when server is null", () => {
39
42
  const local = {
@@ -43,6 +46,7 @@ describe("mergeHarnessConfig", () => {
43
46
  assert.deepStrictEqual(result.preHooks, local.preHooks);
44
47
  assert.deepStrictEqual(result.postHooks, []);
45
48
  assert.strictEqual(result.qualityGate, null);
49
+ assert.deepStrictEqual(result.conventionIds, []);
46
50
  });
47
51
  test("local overrides server at field level", () => {
48
52
  const local = {
@@ -71,6 +75,26 @@ describe("mergeHarnessConfig", () => {
71
75
  const result = mergeHarnessConfig(local, server);
72
76
  assert.strictEqual(result.qualityGate, null);
73
77
  });
78
+ test("local conventionIds overrides server conventionIds", () => {
79
+ const local = {
80
+ conventionIds: ["local-conv-1", "local-conv-2"]
81
+ };
82
+ const server = {
83
+ conventionIds: ["server-conv-1"]
84
+ };
85
+ const result = mergeHarnessConfig(local, server);
86
+ assert.deepStrictEqual(result.conventionIds, ["local-conv-1", "local-conv-2"]);
87
+ });
88
+ test("falls back to server conventionIds when local omits it", () => {
89
+ const local = {
90
+ preHooks: [{ name: "test", command: "npm test", onFailure: "warn" }]
91
+ };
92
+ const server = {
93
+ conventionIds: ["server-conv-1"]
94
+ };
95
+ const result = mergeHarnessConfig(local, server);
96
+ assert.deepStrictEqual(result.conventionIds, ["server-conv-1"]);
97
+ });
74
98
  });
75
99
  // ---------------------------------------------------------------------------
76
100
  // loadLocalHarnessConfig
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.test.js","sourceRoot":"","sources":["../../src/harness/config-loader.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-loader.test.js","sourceRoot":"","sources":["../../src/harness/config-loader.test.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,8 @@ export type HookDefinition = {
11
11
  name: string;
12
12
  command: string;
13
13
  onFailure: HookFailureAction;
14
+ conventionTrigger?: string;
15
+ conventionId?: string;
14
16
  };
15
17
  /** Post-hook quality gate configuration */
16
18
  export type QualityGateConfig = {
@@ -22,12 +24,14 @@ export type HarnessConfig = {
22
24
  preHooks: HookDefinition[];
23
25
  postHooks: HookDefinition[];
24
26
  qualityGate: QualityGateConfig | null;
27
+ conventionIds: string[];
25
28
  };
26
29
  /** Result of parsing the local harness.yml file */
27
30
  export type HarnessYml = {
28
31
  preHooks?: HookDefinition[];
29
32
  postHooks?: HookDefinition[];
30
33
  qualityGate?: QualityGateConfig | null;
34
+ conventionIds?: string[];
31
35
  };
32
36
  /** Shape returned by GET /api/harness-configs/:projectId */
33
37
  export type ServerHarnessConfig = {
package/dist/types.d.ts CHANGED
@@ -60,6 +60,13 @@ export type ClaimResult = {
60
60
  ok: boolean;
61
61
  conflict: boolean;
62
62
  };
63
+ export type ConventionMeta = {
64
+ id: string;
65
+ filePath: string;
66
+ trigger: string | null;
67
+ title: string;
68
+ description: string | null;
69
+ };
63
70
  export type TriggerRuntime = {
64
71
  triggerId: string;
65
72
  agentConfigId: string;
@@ -71,6 +78,9 @@ export type TriggerRuntime = {
71
78
  useWorktree: boolean;
72
79
  baseBranch: string | null;
73
80
  worktreeId: string | null;
81
+ conventions?: ConventionMeta[];
82
+ planType?: string | null;
83
+ harnessConfigId?: string | null;
74
84
  };
75
85
  export type TriggerLogLevel = "INFO" | "WARN" | "ERROR";
76
86
  export type TriggerLogInput = {
@@ -0,0 +1,7 @@
1
+ import type { ConventionMeta } from "../types.js";
2
+ type EvaluationContext = {
3
+ authPath: string;
4
+ planType: string | null;
5
+ };
6
+ export declare const evaluateConventionTriggers: (conventions: ConventionMeta[], context: EvaluationContext) => ConventionMeta[];
7
+ export {};
@@ -0,0 +1,113 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { matchesGlob } from "node:path";
3
+ import { logger } from "../logger.js";
4
+ const parseConditionalTrigger = (trigger) => {
5
+ const parts = trigger.split("|").map((p) => p.trim()).filter(Boolean);
6
+ const filePatterns = [];
7
+ const taskTypes = [];
8
+ for (const part of parts) {
9
+ if (part.startsWith("file:")) {
10
+ const pattern = part.slice(5).trim();
11
+ if (pattern.length > 0)
12
+ filePatterns.push(pattern);
13
+ }
14
+ else if (part.startsWith("task:")) {
15
+ const taskType = part.slice(5).trim().toUpperCase();
16
+ if (taskType.length > 0)
17
+ taskTypes.push(taskType);
18
+ }
19
+ }
20
+ if (filePatterns.length > 0 && taskTypes.length > 0) {
21
+ return { type: "composite", filePatterns, taskTypes };
22
+ }
23
+ if (filePatterns.length > 0)
24
+ return { type: "file", patterns: filePatterns };
25
+ if (taskTypes.length > 0)
26
+ return { type: "task", taskTypes };
27
+ return null;
28
+ };
29
+ const getChangedFiles = (authPath) => {
30
+ try {
31
+ const output = execFileSync("git", ["diff", "--name-only", "HEAD"], {
32
+ cwd: authPath,
33
+ encoding: "utf8",
34
+ timeout: 10_000,
35
+ });
36
+ const statusOutput = execFileSync("git", ["ls-files", "--others", "--exclude-standard"], {
37
+ cwd: authPath,
38
+ encoding: "utf8",
39
+ timeout: 10_000,
40
+ });
41
+ const files = [...output.split("\n"), ...statusOutput.split("\n")]
42
+ .map((f) => f.trim())
43
+ .filter(Boolean);
44
+ return Array.from(new Set(files));
45
+ }
46
+ catch (error) {
47
+ logger.warn("Failed to get changed files for convention evaluation", {
48
+ authPath,
49
+ error: error instanceof Error ? error.message : String(error),
50
+ });
51
+ return [];
52
+ }
53
+ };
54
+ const matchesFilePatterns = (changedFiles, patterns) => {
55
+ return changedFiles.some((file) => patterns.some((pattern) => {
56
+ try {
57
+ return matchesGlob(file, pattern);
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }));
63
+ };
64
+ const matchesTaskType = (planType, taskTypes) => {
65
+ if (!planType)
66
+ return false;
67
+ return taskTypes.includes(planType.toUpperCase());
68
+ };
69
+ export const evaluateConventionTriggers = (conventions, context) => {
70
+ if (conventions.length === 0)
71
+ return [];
72
+ let changedFiles = null;
73
+ const matched = [];
74
+ for (const convention of conventions) {
75
+ if (!convention.trigger)
76
+ continue;
77
+ const condition = parseConditionalTrigger(convention.trigger);
78
+ if (!condition)
79
+ continue;
80
+ switch (condition.type) {
81
+ case "file": {
82
+ if (changedFiles === null)
83
+ changedFiles = getChangedFiles(context.authPath);
84
+ if (matchesFilePatterns(changedFiles, condition.patterns)) {
85
+ matched.push(convention);
86
+ }
87
+ break;
88
+ }
89
+ case "task": {
90
+ if (matchesTaskType(context.planType, condition.taskTypes)) {
91
+ matched.push(convention);
92
+ }
93
+ break;
94
+ }
95
+ case "composite": {
96
+ if (changedFiles === null)
97
+ changedFiles = getChangedFiles(context.authPath);
98
+ if (matchesFilePatterns(changedFiles, condition.filePatterns) ||
99
+ matchesTaskType(context.planType, condition.taskTypes)) {
100
+ matched.push(convention);
101
+ }
102
+ break;
103
+ }
104
+ }
105
+ }
106
+ if (matched.length > 0) {
107
+ logger.info("Convention triggers matched", {
108
+ matched: matched.map((c) => c.title),
109
+ });
110
+ }
111
+ return matched;
112
+ };
113
+ //# sourceMappingURL=convention-evaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convention-evaluator.js","sourceRoot":"","sources":["../../src/utils/convention-evaluator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAatC,MAAM,uBAAuB,GAAG,CAAC,OAAe,EAA0B,EAAE;IAC1E,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACtE,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,SAAS,GAAa,EAAE,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACrC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrD,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YACpD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;IACxD,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAC7E,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC7D,OAAO,IAAI,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,QAAgB,EAAY,EAAE;IACrD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE;YAClE,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QAEH,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,oBAAoB,CAAC,EAAE;YACvF,GAAG,EAAE,QAAQ;YACb,QAAQ,EAAE,MAAM;YAChB,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aAC/D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aACpB,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,uDAAuD,EAAE;YACnE,QAAQ;YACR,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC9D,CAAC,CAAC;QACH,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,YAAsB,EAAE,QAAkB,EAAW,EAAE;IAClF,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAChC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,OAAO,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CACH,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,QAAuB,EAAE,SAAmB,EAAW,EAAE;IAChF,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5B,OAAO,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;AACpD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,WAA6B,EAC7B,OAA0B,EACR,EAAE;IACpB,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAExC,IAAI,YAAY,GAAoB,IAAI,CAAC;IAEzC,MAAM,OAAO,GAAqB,EAAE,CAAC;IAErC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,UAAU,CAAC,OAAO;YAAE,SAAS;QAElC,MAAM,SAAS,GAAG,uBAAuB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAC9D,IAAI,CAAC,SAAS;YAAE,SAAS;QAEzB,QAAQ,SAAS,CAAC,IAAI,EAAE,CAAC;YACvB,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,IAAI,YAAY,KAAK,IAAI;oBAAE,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC5E,IAAI,mBAAmB,CAAC,YAAY,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC1D,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC3B,CAAC;gBACD,MAAM;YACR,CAAC;YACD,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,IAAI,eAAe,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC3D,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC3B,CAAC;gBACD,MAAM;YACR,CAAC;YACD,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,IAAI,YAAY,KAAK,IAAI;oBAAE,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;gBAC5E,IACE,mBAAmB,CAAC,YAAY,EAAE,SAAS,CAAC,YAAY,CAAC;oBACzD,eAAe,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC,EACtD,CAAC;oBACD,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC3B,CAAC;gBACD,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE;YACzC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,190 @@
1
+ import assert from "node:assert/strict";
2
+ import { execFileSync } from "node:child_process";
3
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { describe, it } from "node:test";
7
+ const withGitRepo = async (run) => {
8
+ const dir = await mkdtemp(join(tmpdir(), "conv-eval-"));
9
+ execFileSync("git", ["init", dir], { stdio: "pipe" });
10
+ execFileSync("git", ["-C", dir, "config", "user.email", "test@test.com"], { stdio: "pipe" });
11
+ execFileSync("git", ["-C", dir, "config", "user.name", "Test"], { stdio: "pipe" });
12
+ execFileSync("git", ["-C", dir, "commit", "--allow-empty", "-m", "initial"], { stdio: "pipe" });
13
+ try {
14
+ await run(dir);
15
+ }
16
+ finally {
17
+ await rm(dir, { recursive: true, force: true });
18
+ }
19
+ };
20
+ describe("evaluateConventionTriggers", () => {
21
+ it("returns empty array for empty conventions", async () => {
22
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
23
+ const result = evaluateConventionTriggers([], { authPath: "/tmp", planType: null });
24
+ assert.deepEqual(result, []);
25
+ });
26
+ it("matches task trigger when planType matches", async () => {
27
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
28
+ const taskConvention = {
29
+ id: "conv-task",
30
+ filePath: ".agentteams/rules/testing.md",
31
+ trigger: "task:BUG_FIX",
32
+ title: "Bug Fix Convention",
33
+ description: "Rules for bug fixes",
34
+ };
35
+ const result = evaluateConventionTriggers([taskConvention], {
36
+ authPath: "/tmp/nonexistent",
37
+ planType: "BUG_FIX",
38
+ });
39
+ assert.equal(result.length, 1);
40
+ assert.equal(result[0].id, "conv-task");
41
+ });
42
+ it("does not match task trigger when planType differs", async () => {
43
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
44
+ const taskConvention = {
45
+ id: "conv-task",
46
+ filePath: ".agentteams/rules/testing.md",
47
+ trigger: "task:BUG_FIX",
48
+ title: "Bug Fix Convention",
49
+ description: null,
50
+ };
51
+ const result = evaluateConventionTriggers([taskConvention], {
52
+ authPath: "/tmp/nonexistent",
53
+ planType: "FEATURE",
54
+ });
55
+ assert.equal(result.length, 0);
56
+ });
57
+ it("does not match task trigger when planType is null", async () => {
58
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
59
+ const taskConvention = {
60
+ id: "conv-task",
61
+ filePath: ".agentteams/rules/testing.md",
62
+ trigger: "task:FEATURE",
63
+ title: "Feature Convention",
64
+ description: null,
65
+ };
66
+ const result = evaluateConventionTriggers([taskConvention], {
67
+ authPath: "/tmp/nonexistent",
68
+ planType: null,
69
+ });
70
+ assert.equal(result.length, 0);
71
+ });
72
+ it("skips conventions with null trigger", async () => {
73
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
74
+ const nullTriggerConvention = {
75
+ id: "conv-null",
76
+ filePath: ".agentteams/rules/misc.md",
77
+ trigger: null,
78
+ title: "Misc Convention",
79
+ description: null,
80
+ };
81
+ const result = evaluateConventionTriggers([nullTriggerConvention], {
82
+ authPath: "/tmp/nonexistent",
83
+ planType: "BUG_FIX",
84
+ });
85
+ assert.equal(result.length, 0);
86
+ });
87
+ it("matches composite trigger via task type", async () => {
88
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
89
+ const compositeConvention = {
90
+ id: "conv-composite",
91
+ filePath: ".agentteams/rules/frontend.md",
92
+ trigger: "file:web/src/**|task:FEATURE",
93
+ title: "Frontend Convention",
94
+ description: null,
95
+ };
96
+ const result = evaluateConventionTriggers([compositeConvention], {
97
+ authPath: "/tmp/nonexistent",
98
+ planType: "FEATURE",
99
+ });
100
+ assert.equal(result.length, 1);
101
+ assert.equal(result[0].id, "conv-composite");
102
+ });
103
+ it("matches file trigger when a changed file matches the glob", async () => {
104
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
105
+ await withGitRepo(async (dir) => {
106
+ await mkdir(join(dir, "api/prisma"), { recursive: true });
107
+ await writeFile(join(dir, "api/prisma/schema.prisma"), "model Test {}\n");
108
+ const result = evaluateConventionTriggers([{
109
+ id: "conv-file",
110
+ filePath: ".agentteams/rules/schema.md",
111
+ trigger: "file:api/prisma/**",
112
+ title: "Schema Convention",
113
+ description: null,
114
+ }], {
115
+ authPath: dir,
116
+ planType: null,
117
+ });
118
+ assert.deepEqual(result.map((item) => item.id), ["conv-file"]);
119
+ });
120
+ });
121
+ it("does not match file trigger when changed files fall outside the glob", async () => {
122
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
123
+ await withGitRepo(async (dir) => {
124
+ await mkdir(join(dir, "web/src"), { recursive: true });
125
+ await writeFile(join(dir, "web/src/app.tsx"), "export default function App() { return null; }\n");
126
+ const result = evaluateConventionTriggers([{
127
+ id: "conv-file",
128
+ filePath: ".agentteams/rules/schema.md",
129
+ trigger: "file:api/prisma/**",
130
+ title: "Schema Convention",
131
+ description: null,
132
+ }], {
133
+ authPath: dir,
134
+ planType: null,
135
+ });
136
+ assert.equal(result.length, 0);
137
+ });
138
+ });
139
+ it("matches when any file pattern in a multi-file trigger matches", async () => {
140
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
141
+ await withGitRepo(async (dir) => {
142
+ await mkdir(join(dir, "web/src"), { recursive: true });
143
+ await writeFile(join(dir, "web/src/page.tsx"), "export default function Page() { return null; }\n");
144
+ const result = evaluateConventionTriggers([{
145
+ id: "conv-multi-file",
146
+ filePath: ".agentteams/rules/frontend.md",
147
+ trigger: "file:api/**|file:web/**",
148
+ title: "Frontend Convention",
149
+ description: null,
150
+ }], {
151
+ authPath: dir,
152
+ planType: "BUG_FIX",
153
+ });
154
+ assert.deepEqual(result.map((item) => item.id), ["conv-multi-file"]);
155
+ });
156
+ });
157
+ it("matches composite trigger via file condition when task type does not match", async () => {
158
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
159
+ await withGitRepo(async (dir) => {
160
+ await mkdir(join(dir, "api/src"), { recursive: true });
161
+ await writeFile(join(dir, "api/src/server.ts"), "export const server = true;\n");
162
+ const result = evaluateConventionTriggers([{
163
+ id: "conv-composite-file",
164
+ filePath: ".agentteams/rules/routes.md",
165
+ trigger: "file:api/**|task:FEATURE",
166
+ title: "Route Convention",
167
+ description: null,
168
+ }], {
169
+ authPath: dir,
170
+ planType: "BUG_FIX",
171
+ });
172
+ assert.deepEqual(result.map((item) => item.id), ["conv-composite-file"]);
173
+ });
174
+ });
175
+ it("returns no matches when git diff lookup fails", async () => {
176
+ const { evaluateConventionTriggers } = await import("./convention-evaluator.js");
177
+ const result = evaluateConventionTriggers([{
178
+ id: "conv-file",
179
+ filePath: ".agentteams/rules/schema.md",
180
+ trigger: "file:api/**",
181
+ title: "Schema Convention",
182
+ description: null,
183
+ }], {
184
+ authPath: "/tmp/does-not-exist-for-convention-evaluator",
185
+ planType: null,
186
+ });
187
+ assert.equal(result.length, 0);
188
+ });
189
+ });
190
+ //# sourceMappingURL=convention-evaluator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"convention-evaluator.test.js","sourceRoot":"","sources":["../../src/utils/convention-evaluator.test.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,14 @@
1
1
  import { execFileSync } from "node:child_process";
2
2
  import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync, symlinkSync } from "node:fs";
3
3
  import path from "node:path";
4
+ // 모든 git 호출은 이 헬퍼를 통해 실행해야 한다. windowsHide 누락 시 Windows에서
5
+ // 콘솔 미부착 부모(데몬) 프로세스가 git.exe를 띄울 때 콘솔 창이 잠깐 노출된다.
6
+ function runGit(args, cwd) {
7
+ return execFileSync("git", args, { cwd, stdio: "pipe", windowsHide: true });
8
+ }
4
9
  export function isGitRepo(dirPath) {
5
10
  try {
6
- execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
7
- cwd: dirPath,
8
- stdio: "pipe",
9
- windowsHide: true
10
- });
11
+ runGit(["rev-parse", "--is-inside-work-tree"], dirPath);
11
12
  return true;
12
13
  }
13
14
  catch {
@@ -60,7 +61,7 @@ export function createWorktree(authPath, options) {
60
61
  if (baseBranch) {
61
62
  args.push(baseBranch);
62
63
  }
63
- execFileSync("git", args, { cwd: authPath, stdio: "pipe" });
64
+ runGit(args, authPath);
64
65
  }
65
66
  catch (error) {
66
67
  throw new Error(`Failed to create git worktree for worktreeId ${worktreeId}: ${error instanceof Error ? error.message : String(error)}`);
@@ -105,11 +106,7 @@ export function removeWorktree(authPath, worktreePath, worktreeId) {
105
106
  throw new Error(`Worktree path does not exist: ${worktreePath}`);
106
107
  }
107
108
  try {
108
- execFileSync("git", ["worktree", "remove", worktreePath, "--force"], {
109
- cwd: authPath,
110
- stdio: "pipe",
111
- windowsHide: true
112
- });
109
+ runGit(["worktree", "remove", worktreePath, "--force"], authPath);
113
110
  }
114
111
  catch {
115
112
  // If worktree removal via git fails, try to clean up manually
@@ -117,7 +114,7 @@ export function removeWorktree(authPath, worktreePath, worktreeId) {
117
114
  rmSync(worktreePath, { recursive: true, force: true });
118
115
  }
119
116
  try {
120
- execFileSync("git", ["worktree", "prune"], { cwd: authPath, stdio: "pipe" });
117
+ runGit(["worktree", "prune"], authPath);
121
118
  }
122
119
  catch {
123
120
  // Ignore prune errors
@@ -127,26 +124,14 @@ export function removeWorktree(authPath, worktreePath, worktreeId) {
127
124
  throw new Error(`Worktree directory still exists after removal: ${worktreePath}`);
128
125
  }
129
126
  try {
130
- execFileSync("git", ["branch", "-D", branchName], {
131
- cwd: authPath,
132
- stdio: "pipe",
133
- windowsHide: true
134
- });
127
+ runGit(["branch", "-D", branchName], authPath);
135
128
  }
136
129
  catch {
137
130
  // Branch may not exist or already deleted; ignore
138
131
  }
139
132
  try {
140
- execFileSync("git", ["ls-remote", "--exit-code", "origin", `refs/heads/${branchName}`], {
141
- cwd: authPath,
142
- stdio: "pipe",
143
- windowsHide: true
144
- });
145
- execFileSync("git", ["push", "origin", "--delete", branchName], {
146
- cwd: authPath,
147
- stdio: "pipe",
148
- windowsHide: true
149
- });
133
+ runGit(["ls-remote", "--exit-code", "origin", `refs/heads/${branchName}`], authPath);
134
+ runGit(["push", "origin", "--delete", branchName], authPath);
150
135
  }
151
136
  catch {
152
137
  // Remote branch may not exist or deletion may fail; ignore