npm-cli-gh-issue-preparator 1.2.0 → 1.4.0

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 (24) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/bin/adapter/entry-points/cli/index.js +2 -0
  3. package/bin/adapter/entry-points/cli/index.js.map +1 -1
  4. package/bin/adapter/repositories/Xfce4TerminalCopilotRepository.js +27 -0
  5. package/bin/adapter/repositories/Xfce4TerminalCopilotRepository.js.map +1 -0
  6. package/bin/domain/usecases/StartPreparationUseCase.js +4 -1
  7. package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
  8. package/bin/domain/usecases/adapter-interfaces/CopilotRepository.js +3 -0
  9. package/bin/domain/usecases/adapter-interfaces/CopilotRepository.js.map +1 -0
  10. package/package.json +1 -1
  11. package/src/adapter/entry-points/cli/index.test.ts +39 -0
  12. package/src/adapter/entry-points/cli/index.ts +3 -0
  13. package/src/adapter/repositories/Xfce4TerminalCopilotRepository.test.ts +143 -0
  14. package/src/adapter/repositories/Xfce4TerminalCopilotRepository.ts +32 -0
  15. package/src/domain/usecases/StartPreparationUseCase.test.ts +57 -0
  16. package/src/domain/usecases/StartPreparationUseCase.ts +5 -1
  17. package/src/domain/usecases/adapter-interfaces/CopilotRepository.ts +3 -0
  18. package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
  19. package/types/adapter/repositories/Xfce4TerminalCopilotRepository.d.ts +6 -0
  20. package/types/adapter/repositories/Xfce4TerminalCopilotRepository.d.ts.map +1 -0
  21. package/types/domain/usecases/StartPreparationUseCase.d.ts +1 -0
  22. package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
  23. package/types/domain/usecases/adapter-interfaces/CopilotRepository.d.ts +4 -0
  24. package/types/domain/usecases/adapter-interfaces/CopilotRepository.d.ts.map +1 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ # [1.4.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.3.0...v1.4.0) (2026-01-14)
2
+
3
+
4
+ ### Features
5
+
6
+ * **cli:** add logFilePath to cli parameter ([8e7dba7](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/commit/8e7dba7608cac085883c7beaeca1cd5de490f46e))
7
+
8
+ # [1.3.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.2.0...v1.3.0) (2026-01-12)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * prevent command injection in xfce4-terminal spawn ([0a4e008](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/commit/0a4e008749b293cd1f1d311ad08adfc9f37033c3))
14
+
15
+
16
+ ### Features
17
+
18
+ * **src:** create CopilotRepository ([c79ed81](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/commit/c79ed8127342a5aa58fc2f83b10334bbb0fc6a0d)), closes [#38](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/issues/38)
19
+
1
20
  # [1.2.0](https://github.com/HiromiShikata/npm-cli-gh-issue-preparator/compare/v1.1.0...v1.2.0) (2026-01-12)
2
21
 
3
22
 
@@ -25,6 +25,7 @@ program
25
25
  .requiredOption('--awaitingWorkspaceStatus <status>', 'Status for issues awaiting workspace')
26
26
  .requiredOption('--preparationStatus <status>', 'Status for issues in preparation')
27
27
  .requiredOption('--defaultAgentName <name>', 'Default agent name')
28
+ .option('--logFilePath <path>', 'Path to log file')
28
29
  .action(async (options) => {
29
30
  const token = process.env.GH_TOKEN;
30
31
  if (!token) {
@@ -40,6 +41,7 @@ program
40
41
  awaitingWorkspaceStatus: options.awaitingWorkspaceStatus,
41
42
  preparationStatus: options.preparationStatus,
42
43
  defaultAgentName: options.defaultAgentName,
44
+ logFilePath: options.logFilePath,
43
45
  });
44
46
  });
45
47
  program
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Xfce4TerminalCopilotRepository = void 0;
4
+ const child_process_1 = require("child_process");
5
+ class Xfce4TerminalCopilotRepository {
6
+ escapeForSingleQuotes(str) {
7
+ return str.replace(/'/g, "'\\''");
8
+ }
9
+ run(prompt, model, processTitle) {
10
+ const escapedPrompt = this.escapeForSingleQuotes(prompt);
11
+ const escapedTitle = this.escapeForSingleQuotes(processTitle);
12
+ const innerCommand = `copilot --model ${model} --allow-all-tools -p '${escapedPrompt}'`;
13
+ const escapedInnerCommand = this.escapeForSingleQuotes(innerCommand);
14
+ const title = `gh-issue-preparator: ${escapedTitle}`;
15
+ const child = (0, child_process_1.spawn)('xfce4-terminal', ['-T', title, '-e', `bash -c '${escapedInnerCommand}'`], {
16
+ detached: true,
17
+ stdio: 'ignore',
18
+ });
19
+ child.on('error', () => {
20
+ // Intentionally empty - fire-and-forget behavior
21
+ // Errors are silently ignored as this is a background terminal spawn
22
+ });
23
+ child.unref();
24
+ }
25
+ }
26
+ exports.Xfce4TerminalCopilotRepository = Xfce4TerminalCopilotRepository;
27
+ //# sourceMappingURL=Xfce4TerminalCopilotRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Xfce4TerminalCopilotRepository.js","sourceRoot":"","sources":["../../../src/adapter/repositories/Xfce4TerminalCopilotRepository.ts"],"names":[],"mappings":";;;AACA,iDAAsC;AAEtC,MAAa,8BAA8B;IACjC,qBAAqB,CAAC,GAAW;QACvC,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,GAAG,CAAC,MAAc,EAAE,KAAmB,EAAE,YAAoB;QAC3D,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;QACzD,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAAC;QAC9D,MAAM,YAAY,GAAG,mBAAmB,KAAK,0BAA0B,aAAa,GAAG,CAAC;QACxF,MAAM,mBAAmB,GAAG,IAAI,CAAC,qBAAqB,CAAC,YAAY,CAAC,CAAC;QACrE,MAAM,KAAK,GAAG,wBAAwB,YAAY,EAAE,CAAC;QAErD,MAAM,KAAK,GAAG,IAAA,qBAAK,EACjB,gBAAgB,EAChB,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,mBAAmB,GAAG,CAAC,EACvD;YACE,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,QAAQ;SAChB,CACF,CAAC;QAEF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACrB,iDAAiD;YACjD,qEAAqE;QACvE,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,KAAK,EAAE,CAAC;IAChB,CAAC;CACF;AA5BD,wEA4BC"}
@@ -24,7 +24,10 @@ class StartPreparationUseCase {
24
24
  .trim() || params.defaultAgentName;
25
25
  issue.status = params.preparationStatus;
26
26
  await this.issueRepository.update(issue, project);
27
- await this.localCommandRunner.runCommand(`aw ${issue.url} ${agent} ${project.url}`);
27
+ const logFilePathArg = params.logFilePath
28
+ ? `--logFilePath ${params.logFilePath}`
29
+ : '';
30
+ await this.localCommandRunner.runCommand(`aw ${issue.url} ${agent} ${project.url}${logFilePathArg ? ` ${logFilePathArg}` : ''}`);
28
31
  }
29
32
  };
30
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":";;;AAIA,MAAa,uBAAuB;IAElC,YACmB,iBAAoC,EACpC,eAAgC,EAChC,kBAAsC;QAFtC,sBAAiB,GAAjB,iBAAiB,CAAmB;QACpC,oBAAe,GAAf,eAAe,CAAiB;QAChC,uBAAkB,GAAlB,kBAAkB,CAAoB;QAJzD,gCAA2B,GAAG,CAAC,CAAC;QAOhC,QAAG,GAAG,KAAK,EAAE,MAKZ,EAAiB,EAAE;YAClB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAEzE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAEnE,MAAM,uBAAuB,GAAG,SAAS,CAAC,MAAM,CAC9C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,uBAAuB,CAC3D,CAAC;YACF,MAAM,4BAA4B,GAAG,SAAS,CAAC,MAAM,CACnD,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,iBAAiB,CACrD,CAAC,MAAM,CAAC;YAET,KACE,IAAI,CAAC,GAAG,4BAA4B,EACpC,CAAC;gBACD,IAAI,CAAC,GAAG,CACN,IAAI,CAAC,2BAA2B,EAChC,uBAAuB,CAAC,MAAM,GAAG,4BAA4B,CAC9D,EACD,CAAC,EAAE,EACH,CAAC;gBACD,MAAM,KAAK,GAAG,uBAAuB,CAAC,GAAG,EAAE,CAAC;gBAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,MAAM;gBACR,CAAC;gBACD,MAAM,KAAK,GACT,KAAK,CAAC,MAAM;qBACT,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;oBAC/C,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;qBACzB,IAAI,EAAE,IAAI,MAAM,CAAC,gBAAgB,CAAC;gBACvC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC;gBACxC,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAElD,MAAM,IAAI,CAAC,kBAAkB,CAAC,UAAU,CACtC,MAAM,KAAK,CAAC,GAAG,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,EAAE,CAC1C,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;IA5CC,CAAC;CA6CL;AAnDD,0DAmDC"}
1
+ {"version":3,"file":"StartPreparationUseCase.js","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":";;;AAIA,MAAa,uBAAuB;IAElC,YACmB,iBAAoC,EACpC,eAAgC,EAChC,kBAAsC;QAFtC,sBAAiB,GAAjB,iBAAiB,CAAmB;QACpC,oBAAe,GAAf,eAAe,CAAiB;QAChC,uBAAkB,GAAlB,kBAAkB,CAAoB;QAJzD,gCAA2B,GAAG,CAAC,CAAC;QAOhC,QAAG,GAAG,KAAK,EAAE,MAMZ,EAAiB,EAAE;YAClB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAEzE,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAEnE,MAAM,uBAAuB,GAAG,SAAS,CAAC,MAAM,CAC9C,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,uBAAuB,CAC3D,CAAC;YACF,MAAM,4BAA4B,GAAG,SAAS,CAAC,MAAM,CACnD,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,MAAM,CAAC,iBAAiB,CACrD,CAAC,MAAM,CAAC;YAET,KACE,IAAI,CAAC,GAAG,4BAA4B,EACpC,CAAC;gBACD,IAAI,CAAC,GAAG,CACN,IAAI,CAAC,2BAA2B,EAChC,uBAAuB,CAAC,MAAM,GAAG,4BAA4B,CAC9D,EACD,CAAC,EAAE,EACH,CAAC;gBACD,MAAM,KAAK,GAAG,uBAAuB,CAAC,GAAG,EAAE,CAAC;gBAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;oBACX,MAAM;gBACR,CAAC;gBACD,MAAM,KAAK,GACT,KAAK,CAAC,MAAM;qBACT,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;oBAC/C,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;qBACzB,IAAI,EAAE,IAAI,MAAM,CAAC,gBAAgB,CAAC;gBACvC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC;gBACxC,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAElD,MAAM,cAAc,GAAG,MAAM,CAAC,WAAW;oBACvC,CAAC,CAAC,iBAAiB,MAAM,CAAC,WAAW,EAAE;oBACvC,CAAC,CAAC,EAAE,CAAC;gBACP,MAAM,IAAI,CAAC,kBAAkB,CAAC,UAAU,CACtC,MAAM,KAAK,CAAC,GAAG,IAAI,KAAK,IAAI,OAAO,CAAC,GAAG,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACvF,CAAC;YACJ,CAAC;QACH,CAAC,CAAC;IAhDC,CAAC;CAiDL;AAvDD,0DAuDC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=CopilotRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CopilotRepository.js","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/CopilotRepository.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "npm-cli-gh-issue-preparator",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "scripts": {
@@ -56,6 +56,45 @@ describe('CLI', () => {
56
56
  awaitingWorkspaceStatus: 'Awaiting',
57
57
  preparationStatus: 'Preparing',
58
58
  defaultAgentName: 'agent1',
59
+ logFilePath: undefined,
60
+ });
61
+ });
62
+
63
+ it('should pass logFilePath to StartPreparationUseCase when provided', async () => {
64
+ const mockRun = jest.fn().mockResolvedValue(undefined);
65
+ const MockedStartPreparationUseCase = jest.mocked(StartPreparationUseCase);
66
+
67
+ MockedStartPreparationUseCase.mockImplementation(function (
68
+ this: StartPreparationUseCase,
69
+ ) {
70
+ this.run = mockRun;
71
+ this.maximumPreparingIssuesCount = 6;
72
+ return this;
73
+ });
74
+
75
+ await program.parseAsync([
76
+ 'node',
77
+ 'test',
78
+ 'startDaemon',
79
+ '--projectUrl',
80
+ 'https://github.com/test/project',
81
+ '--awaitingWorkspaceStatus',
82
+ 'Awaiting',
83
+ '--preparationStatus',
84
+ 'Preparing',
85
+ '--defaultAgentName',
86
+ 'agent1',
87
+ '--logFilePath',
88
+ '/path/to/log.txt',
89
+ ]);
90
+
91
+ expect(mockRun).toHaveBeenCalledTimes(1);
92
+ expect(mockRun).toHaveBeenCalledWith({
93
+ projectUrl: 'https://github.com/test/project',
94
+ awaitingWorkspaceStatus: 'Awaiting',
95
+ preparationStatus: 'Preparing',
96
+ defaultAgentName: 'agent1',
97
+ logFilePath: '/path/to/log.txt',
59
98
  });
60
99
  });
61
100
 
@@ -14,6 +14,7 @@ type StartDaemonOptions = {
14
14
  awaitingWorkspaceStatus: string;
15
15
  preparationStatus: string;
16
16
  defaultAgentName: string;
17
+ logFilePath?: string;
17
18
  };
18
19
 
19
20
  type NotifyFinishedOptions = {
@@ -41,6 +42,7 @@ program
41
42
  'Status for issues in preparation',
42
43
  )
43
44
  .requiredOption('--defaultAgentName <name>', 'Default agent name')
45
+ .option('--logFilePath <path>', 'Path to log file')
44
46
  .action(async (options: StartDaemonOptions) => {
45
47
  const token = process.env.GH_TOKEN;
46
48
  if (!token) {
@@ -63,6 +65,7 @@ program
63
65
  awaitingWorkspaceStatus: options.awaitingWorkspaceStatus,
64
66
  preparationStatus: options.preparationStatus,
65
67
  defaultAgentName: options.defaultAgentName,
68
+ logFilePath: options.logFilePath,
66
69
  });
67
70
  });
68
71
 
@@ -0,0 +1,143 @@
1
+ const mockUnref = jest.fn();
2
+ const mockOn = jest.fn();
3
+ const mockSpawn = jest.fn(() => ({ on: mockOn, unref: mockUnref }));
4
+
5
+ jest.mock('child_process', () => ({
6
+ spawn: mockSpawn,
7
+ }));
8
+
9
+ import { Xfce4TerminalCopilotRepository } from './Xfce4TerminalCopilotRepository';
10
+
11
+ describe('Xfce4TerminalCopilotRepository', () => {
12
+ let repository: Xfce4TerminalCopilotRepository;
13
+
14
+ beforeEach(() => {
15
+ jest.clearAllMocks();
16
+ repository = new Xfce4TerminalCopilotRepository();
17
+ });
18
+
19
+ describe('run', () => {
20
+ it('should spawn xfce4-terminal with correct arguments', () => {
21
+ repository.run('test prompt', 'gpt-5-mini', 'test-process');
22
+
23
+ expect(mockSpawn).toHaveBeenCalledWith(
24
+ 'xfce4-terminal',
25
+ [
26
+ '-T',
27
+ 'gh-issue-preparator: test-process',
28
+ '-e',
29
+ "bash -c 'copilot --model gpt-5-mini --allow-all-tools -p '\\''test prompt'\\'''",
30
+ ],
31
+ {
32
+ detached: true,
33
+ stdio: 'ignore',
34
+ },
35
+ );
36
+ expect(mockOn).toHaveBeenCalledWith('error', expect.any(Function));
37
+ expect(mockUnref).toHaveBeenCalled();
38
+ });
39
+
40
+ it('should escape single quotes in prompt to prevent command injection', () => {
41
+ repository.run(
42
+ "prompt with 'single quotes'",
43
+ 'gpt-5-mini',
44
+ 'test-process',
45
+ );
46
+
47
+ expect(mockSpawn).toHaveBeenCalledWith(
48
+ 'xfce4-terminal',
49
+ [
50
+ '-T',
51
+ 'gh-issue-preparator: test-process',
52
+ '-e',
53
+ "bash -c 'copilot --model gpt-5-mini --allow-all-tools -p '\\''prompt with '\\''\\'\\'''\\''single quotes'\\''\\'\\'''\\'''\\'''",
54
+ ],
55
+ {
56
+ detached: true,
57
+ stdio: 'ignore',
58
+ },
59
+ );
60
+ });
61
+
62
+ it('should escape backticks in prompt to prevent command injection', () => {
63
+ repository.run('prompt with `backticks`', 'gpt-5-mini', 'test-process');
64
+
65
+ expect(mockSpawn).toHaveBeenCalledWith(
66
+ 'xfce4-terminal',
67
+ [
68
+ '-T',
69
+ 'gh-issue-preparator: test-process',
70
+ '-e',
71
+ "bash -c 'copilot --model gpt-5-mini --allow-all-tools -p '\\''prompt with `backticks`'\\'''",
72
+ ],
73
+ {
74
+ detached: true,
75
+ stdio: 'ignore',
76
+ },
77
+ );
78
+ });
79
+
80
+ it('should escape command substitution in prompt to prevent injection', () => {
81
+ repository.run('prompt with $(whoami)', 'gpt-5-mini', 'test-process');
82
+
83
+ expect(mockSpawn).toHaveBeenCalledWith(
84
+ 'xfce4-terminal',
85
+ [
86
+ '-T',
87
+ 'gh-issue-preparator: test-process',
88
+ '-e',
89
+ "bash -c 'copilot --model gpt-5-mini --allow-all-tools -p '\\''prompt with $(whoami)'\\'''",
90
+ ],
91
+ {
92
+ detached: true,
93
+ stdio: 'ignore',
94
+ },
95
+ );
96
+ });
97
+
98
+ it('should escape single quotes in processTitle', () => {
99
+ repository.run('prompt', 'gpt-5-mini', "title with 'quotes'");
100
+
101
+ expect(mockSpawn).toHaveBeenCalledWith(
102
+ 'xfce4-terminal',
103
+ [
104
+ '-T',
105
+ "gh-issue-preparator: title with '\\''quotes'\\''",
106
+ '-e',
107
+ "bash -c 'copilot --model gpt-5-mini --allow-all-tools -p '\\''prompt'\\'''",
108
+ ],
109
+ {
110
+ detached: true,
111
+ stdio: 'ignore',
112
+ },
113
+ );
114
+ });
115
+
116
+ it('should set correct window title', () => {
117
+ repository.run('prompt', 'gpt-5-mini', 'my-custom-title');
118
+
119
+ expect(mockSpawn).toHaveBeenCalledWith(
120
+ 'xfce4-terminal',
121
+ expect.arrayContaining(['-T', 'gh-issue-preparator: my-custom-title']),
122
+ expect.any(Object),
123
+ );
124
+ });
125
+
126
+ it('should register error handler and silently ignore errors', () => {
127
+ let capturedHandler: ((error: Error) => void) | undefined;
128
+ mockOn.mockImplementation(
129
+ (event: string, handler: (error: Error) => void) => {
130
+ if (event === 'error') {
131
+ capturedHandler = handler;
132
+ }
133
+ },
134
+ );
135
+
136
+ repository.run('test', 'gpt-5-mini', 'test');
137
+
138
+ expect(mockOn).toHaveBeenCalledWith('error', expect.any(Function));
139
+ expect(capturedHandler).toBeDefined();
140
+ expect(() => capturedHandler?.(new Error('spawn failed'))).not.toThrow();
141
+ });
142
+ });
143
+ });
@@ -0,0 +1,32 @@
1
+ import { CopilotRepository } from '../../domain/usecases/adapter-interfaces/CopilotRepository';
2
+ import { spawn } from 'child_process';
3
+
4
+ export class Xfce4TerminalCopilotRepository implements CopilotRepository {
5
+ private escapeForSingleQuotes(str: string): string {
6
+ return str.replace(/'/g, "'\\''");
7
+ }
8
+
9
+ run(prompt: string, model: 'gpt-5-mini', processTitle: string): void {
10
+ const escapedPrompt = this.escapeForSingleQuotes(prompt);
11
+ const escapedTitle = this.escapeForSingleQuotes(processTitle);
12
+ const innerCommand = `copilot --model ${model} --allow-all-tools -p '${escapedPrompt}'`;
13
+ const escapedInnerCommand = this.escapeForSingleQuotes(innerCommand);
14
+ const title = `gh-issue-preparator: ${escapedTitle}`;
15
+
16
+ const child = spawn(
17
+ 'xfce4-terminal',
18
+ ['-T', title, '-e', `bash -c '${escapedInnerCommand}'`],
19
+ {
20
+ detached: true,
21
+ stdio: 'ignore',
22
+ },
23
+ );
24
+
25
+ child.on('error', () => {
26
+ // Intentionally empty - fire-and-forget behavior
27
+ // Errors are silently ignored as this is a background terminal spawn
28
+ });
29
+
30
+ child.unref();
31
+ }
32
+ }
@@ -142,6 +142,63 @@ describe('StartPreparationUseCase', () => {
142
142
  expect(issue7UpdateCalls).toHaveLength(0);
143
143
  expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(0);
144
144
  });
145
+ it('should append logFilePath to aw command when provided', async () => {
146
+ const awaitingIssues: Issue[] = [
147
+ {
148
+ id: '1',
149
+ url: 'url1',
150
+ title: 'Issue 1',
151
+ labels: ['category:impl'],
152
+ status: 'Awaiting Workspace',
153
+ },
154
+ ];
155
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
156
+ mockIssueRepository.getAllOpened.mockResolvedValueOnce(awaitingIssues);
157
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
158
+ stdout: '',
159
+ stderr: '',
160
+ exitCode: 0,
161
+ });
162
+ await useCase.run({
163
+ projectUrl: 'https://github.com/user/repo',
164
+ awaitingWorkspaceStatus: 'Awaiting Workspace',
165
+ preparationStatus: 'Preparation',
166
+ defaultAgentName: 'agent1',
167
+ logFilePath: '/path/to/log.txt',
168
+ });
169
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
170
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][0]).toBe(
171
+ 'aw url1 impl https://github.com/user/repo --logFilePath /path/to/log.txt',
172
+ );
173
+ });
174
+ it('should not append logFilePath to aw command when not provided', async () => {
175
+ const awaitingIssues: Issue[] = [
176
+ {
177
+ id: '1',
178
+ url: 'url1',
179
+ title: 'Issue 1',
180
+ labels: ['category:impl'],
181
+ status: 'Awaiting Workspace',
182
+ },
183
+ ];
184
+ mockProjectRepository.getByUrl.mockResolvedValue(mockProject);
185
+ mockIssueRepository.getAllOpened.mockResolvedValueOnce(awaitingIssues);
186
+ mockLocalCommandRunner.runCommand.mockResolvedValue({
187
+ stdout: '',
188
+ stderr: '',
189
+ exitCode: 0,
190
+ });
191
+ await useCase.run({
192
+ projectUrl: 'https://github.com/user/repo',
193
+ awaitingWorkspaceStatus: 'Awaiting Workspace',
194
+ preparationStatus: 'Preparation',
195
+ defaultAgentName: 'agent1',
196
+ });
197
+ expect(mockLocalCommandRunner.runCommand.mock.calls).toHaveLength(1);
198
+ expect(mockLocalCommandRunner.runCommand.mock.calls[0][0]).toBe(
199
+ 'aw url1 impl https://github.com/user/repo',
200
+ );
201
+ });
145
202
  it('should handle defensive break when pop returns undefined', async () => {
146
203
  const awaitingIssue: Issue = {
147
204
  id: '1',
@@ -15,6 +15,7 @@ export class StartPreparationUseCase {
15
15
  awaitingWorkspaceStatus: string;
16
16
  preparationStatus: string;
17
17
  defaultAgentName: string;
18
+ logFilePath?: string;
18
19
  }): Promise<void> => {
19
20
  const project = await this.projectRepository.getByUrl(params.projectUrl);
20
21
 
@@ -48,8 +49,11 @@ export class StartPreparationUseCase {
48
49
  issue.status = params.preparationStatus;
49
50
  await this.issueRepository.update(issue, project);
50
51
 
52
+ const logFilePathArg = params.logFilePath
53
+ ? `--logFilePath ${params.logFilePath}`
54
+ : '';
51
55
  await this.localCommandRunner.runCommand(
52
- `aw ${issue.url} ${agent} ${project.url}`,
56
+ `aw ${issue.url} ${agent} ${project.url}${logFilePathArg ? ` ${logFilePathArg}` : ''}`,
53
57
  );
54
58
  }
55
59
  };
@@ -0,0 +1,3 @@
1
+ export interface CopilotRepository {
2
+ run(prompt: string, model: 'gpt-5-mini', processTitle: string): void;
3
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAoF9B,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapter/entry-points/cli/index.ts"],"names":[],"mappings":";AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsBpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAsF9B,OAAO,EAAE,OAAO,EAAE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { CopilotRepository } from '../../domain/usecases/adapter-interfaces/CopilotRepository';
2
+ export declare class Xfce4TerminalCopilotRepository implements CopilotRepository {
3
+ private escapeForSingleQuotes;
4
+ run(prompt: string, model: 'gpt-5-mini', processTitle: string): void;
5
+ }
6
+ //# sourceMappingURL=Xfce4TerminalCopilotRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Xfce4TerminalCopilotRepository.d.ts","sourceRoot":"","sources":["../../../src/adapter/repositories/Xfce4TerminalCopilotRepository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4DAA4D,CAAC;AAG/F,qBAAa,8BAA+B,YAAW,iBAAiB;IACtE,OAAO,CAAC,qBAAqB;IAI7B,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;CAuBrE"}
@@ -12,6 +12,7 @@ export declare class StartPreparationUseCase {
12
12
  awaitingWorkspaceStatus: string;
13
13
  preparationStatus: string;
14
14
  defaultAgentName: string;
15
+ logFilePath?: string;
15
16
  }) => Promise<void>;
16
17
  }
17
18
  //# sourceMappingURL=StartPreparationUseCase.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"StartPreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,qBAAa,uBAAuB;IAGhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAJrC,2BAA2B,SAAK;gBAEb,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,EAAE,eAAe,EAChC,kBAAkB,EAAE,kBAAkB;IAGzD,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,uBAAuB,EAAE,MAAM,CAAC;QAChC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;KAC1B,KAAG,OAAO,CAAC,IAAI,CAAC,CAqCf;CACH"}
1
+ {"version":3,"file":"StartPreparationUseCase.d.ts","sourceRoot":"","sources":["../../../src/domain/usecases/StartPreparationUseCase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAE7E,qBAAa,uBAAuB;IAGhC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAJrC,2BAA2B,SAAK;gBAEb,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,EAAE,eAAe,EAChC,kBAAkB,EAAE,kBAAkB;IAGzD,GAAG,GAAU,QAAQ;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,uBAAuB,EAAE,MAAM,CAAC;QAChC,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,KAAG,OAAO,CAAC,IAAI,CAAC,CAwCf;CACH"}
@@ -0,0 +1,4 @@
1
+ export interface CopilotRepository {
2
+ run(prompt: string, model: 'gpt-5-mini', processTitle: string): void;
3
+ }
4
+ //# sourceMappingURL=CopilotRepository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CopilotRepository.d.ts","sourceRoot":"","sources":["../../../../src/domain/usecases/adapter-interfaces/CopilotRepository.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACtE"}