reviewflow 3.29.0 → 3.31.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 (115) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/dashboard/index.html +54 -26
  3. package/dist/dashboard/modules/emberAvatar.d.ts +134 -0
  4. package/dist/dashboard/modules/emberAvatar.d.ts.map +1 -0
  5. package/dist/dashboard/modules/emberAvatar.js +192 -0
  6. package/dist/dashboard/modules/emberAvatar.js.map +1 -0
  7. package/dist/dashboard/modules/emberAvatarRenderer.d.ts +42 -0
  8. package/dist/dashboard/modules/emberAvatarRenderer.d.ts.map +1 -0
  9. package/dist/dashboard/modules/emberAvatarRenderer.js +119 -0
  10. package/dist/dashboard/modules/emberAvatarRenderer.js.map +1 -0
  11. package/dist/dashboard/styles.css +183 -8
  12. package/dist/frameworks/claude/claudeInvoker.d.ts +7 -0
  13. package/dist/frameworks/claude/claudeInvoker.d.ts.map +1 -1
  14. package/dist/frameworks/claude/claudeInvoker.js +1 -1
  15. package/dist/frameworks/claude/claudeInvoker.js.map +1 -1
  16. package/dist/main/routes.d.ts.map +1 -1
  17. package/dist/main/routes.js +6 -16
  18. package/dist/main/routes.js.map +1 -1
  19. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.gateway.d.ts +1 -1
  20. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.gateway.d.ts.map +1 -1
  21. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.guard.d.ts +1 -1
  22. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.d.ts +2 -0
  23. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.d.ts.map +1 -1
  24. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.js +1 -1
  25. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.js.map +1 -1
  26. package/dist/modules/ember-chat/entities/emberAnswer/emberAnswerTransport.gateway.d.ts +24 -0
  27. package/dist/modules/ember-chat/entities/emberAnswer/emberAnswerTransport.gateway.d.ts.map +1 -0
  28. package/dist/modules/ember-chat/entities/emberAnswer/emberAnswerTransport.gateway.js +2 -0
  29. package/dist/modules/ember-chat/entities/emberAnswer/emberAnswerTransport.gateway.js.map +1 -0
  30. package/dist/modules/ember-chat/interface-adapters/controllers/http/emberChat.routes.d.ts +2 -3
  31. package/dist/modules/ember-chat/interface-adapters/controllers/http/emberChat.routes.d.ts.map +1 -1
  32. package/dist/modules/ember-chat/interface-adapters/controllers/http/emberChat.routes.js +6 -4
  33. package/dist/modules/ember-chat/interface-adapters/controllers/http/emberChat.routes.js.map +1 -1
  34. package/dist/modules/ember-chat/interface-adapters/gateways/emberAnswerTransport.claude.gateway.d.ts +46 -0
  35. package/dist/modules/ember-chat/interface-adapters/gateways/emberAnswerTransport.claude.gateway.d.ts.map +1 -0
  36. package/dist/modules/ember-chat/interface-adapters/gateways/emberAnswerTransport.claude.gateway.js +176 -0
  37. package/dist/modules/ember-chat/interface-adapters/gateways/emberAnswerTransport.claude.gateway.js.map +1 -0
  38. package/dist/modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.d.ts +2 -1
  39. package/dist/modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.d.ts.map +1 -1
  40. package/dist/modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.js +8 -2
  41. package/dist/modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.js.map +1 -1
  42. package/dist/modules/ember-chat/interface-adapters/presenters/emberStatus.presenter.d.ts +1 -1
  43. package/dist/modules/ember-chat/interface-adapters/presenters/emberStatus.presenter.d.ts.map +1 -1
  44. package/dist/modules/ember-chat/services/emberSystemPrompt.d.ts.map +1 -1
  45. package/dist/modules/ember-chat/services/emberSystemPrompt.js +47 -4
  46. package/dist/modules/ember-chat/services/emberSystemPrompt.js.map +1 -1
  47. package/dist/modules/ember-chat/usecases/askEmber/askEmber.usecase.d.ts +5 -4
  48. package/dist/modules/ember-chat/usecases/askEmber/askEmber.usecase.d.ts.map +1 -1
  49. package/dist/modules/ember-chat/usecases/askEmber/askEmber.usecase.js +61 -9
  50. package/dist/modules/ember-chat/usecases/askEmber/askEmber.usecase.js.map +1 -1
  51. package/dist/modules/ember-chat/usecases/askEmber/emberStream.d.ts +8 -0
  52. package/dist/modules/ember-chat/usecases/askEmber/emberStream.d.ts.map +1 -0
  53. package/dist/modules/ember-chat/usecases/askEmber/emberStream.js +2 -0
  54. package/dist/modules/ember-chat/usecases/askEmber/emberStream.js.map +1 -0
  55. package/dist/tests/acceptance/190-ember-live-answers-subscription.acceptance.test.d.ts +2 -0
  56. package/dist/tests/acceptance/190-ember-live-answers-subscription.acceptance.test.d.ts.map +1 -0
  57. package/dist/tests/acceptance/190-ember-live-answers-subscription.acceptance.test.js +158 -0
  58. package/dist/tests/acceptance/190-ember-live-answers-subscription.acceptance.test.js.map +1 -0
  59. package/dist/tests/stubs/emberAnswerTransport.stub.d.ts +21 -0
  60. package/dist/tests/stubs/emberAnswerTransport.stub.d.ts.map +1 -0
  61. package/dist/tests/stubs/emberAnswerTransport.stub.js +54 -0
  62. package/dist/tests/stubs/emberAnswerTransport.stub.js.map +1 -0
  63. package/dist/tests/units/dashboard/modules/emberAvatar.test.d.ts +2 -0
  64. package/dist/tests/units/dashboard/modules/emberAvatar.test.d.ts.map +1 -0
  65. package/dist/tests/units/dashboard/modules/emberAvatar.test.js +74 -0
  66. package/dist/tests/units/dashboard/modules/emberAvatar.test.js.map +1 -0
  67. package/dist/tests/units/dashboard/modules/emberAvatarRenderer.test.d.ts +2 -0
  68. package/dist/tests/units/dashboard/modules/emberAvatarRenderer.test.d.ts.map +1 -0
  69. package/dist/tests/units/dashboard/modules/emberAvatarRenderer.test.js +44 -0
  70. package/dist/tests/units/dashboard/modules/emberAvatarRenderer.test.js.map +1 -0
  71. package/dist/tests/units/modules/ember-chat/controllers/emberChat.routes.test.js +21 -14
  72. package/dist/tests/units/modules/ember-chat/controllers/emberChat.routes.test.js.map +1 -1
  73. package/dist/tests/units/modules/ember-chat/gateways/emberStreamJson.parser.test.js +13 -0
  74. package/dist/tests/units/modules/ember-chat/gateways/emberStreamJson.parser.test.js.map +1 -1
  75. package/dist/tests/units/modules/ember-chat/services/emberSystemPrompt.test.js +19 -0
  76. package/dist/tests/units/modules/ember-chat/services/emberSystemPrompt.test.js.map +1 -1
  77. package/dist/tests/units/modules/ember-chat/usecases/askEmber.usecase.test.js +53 -20
  78. package/dist/tests/units/modules/ember-chat/usecases/askEmber.usecase.test.js.map +1 -1
  79. package/package.json +1 -1
  80. package/dist/modules/ember-chat/entities/emberSession/emberSession.schema.d.ts +0 -7
  81. package/dist/modules/ember-chat/entities/emberSession/emberSession.schema.d.ts.map +0 -1
  82. package/dist/modules/ember-chat/entities/emberSession/emberSession.schema.js +0 -3
  83. package/dist/modules/ember-chat/entities/emberSession/emberSession.schema.js.map +0 -1
  84. package/dist/modules/ember-chat/entities/emberSession/emberSessionState.d.ts +0 -13
  85. package/dist/modules/ember-chat/entities/emberSession/emberSessionState.d.ts.map +0 -1
  86. package/dist/modules/ember-chat/entities/emberSession/emberSessionState.js +0 -35
  87. package/dist/modules/ember-chat/entities/emberSession/emberSessionState.js.map +0 -1
  88. package/dist/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.d.ts +0 -26
  89. package/dist/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.d.ts.map +0 -1
  90. package/dist/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.js +0 -2
  91. package/dist/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.js.map +0 -1
  92. package/dist/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.d.ts +0 -13
  93. package/dist/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.d.ts.map +0 -1
  94. package/dist/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.js +0 -130
  95. package/dist/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.js.map +0 -1
  96. package/dist/modules/ember-chat/usecases/emberSession/emberSessionRegistry.d.ts +0 -36
  97. package/dist/modules/ember-chat/usecases/emberSession/emberSessionRegistry.d.ts.map +0 -1
  98. package/dist/modules/ember-chat/usecases/emberSession/emberSessionRegistry.js +0 -59
  99. package/dist/modules/ember-chat/usecases/emberSession/emberSessionRegistry.js.map +0 -1
  100. package/dist/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.d.ts +0 -2
  101. package/dist/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.d.ts.map +0 -1
  102. package/dist/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.js +0 -124
  103. package/dist/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.js.map +0 -1
  104. package/dist/tests/stubs/emberSessionTransport.stub.d.ts +0 -18
  105. package/dist/tests/stubs/emberSessionTransport.stub.d.ts.map +0 -1
  106. package/dist/tests/stubs/emberSessionTransport.stub.js +0 -75
  107. package/dist/tests/stubs/emberSessionTransport.stub.js.map +0 -1
  108. package/dist/tests/units/modules/ember-chat/entities/emberSessionState.test.d.ts +0 -2
  109. package/dist/tests/units/modules/ember-chat/entities/emberSessionState.test.d.ts.map +0 -1
  110. package/dist/tests/units/modules/ember-chat/entities/emberSessionState.test.js +0 -42
  111. package/dist/tests/units/modules/ember-chat/entities/emberSessionState.test.js.map +0 -1
  112. package/dist/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.d.ts +0 -2
  113. package/dist/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.d.ts.map +0 -1
  114. package/dist/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.js +0 -88
  115. package/dist/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.js.map +0 -1
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=189-ember-readonly-review-chat.acceptance.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"189-ember-readonly-review-chat.acceptance.test.d.ts","sourceRoot":"","sources":["../../../src/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.ts"],"names":[],"mappings":""}
@@ -1,124 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { ProjectStatsFactory, ReviewStatsFactory } from '../../tests/factories/projectStats.factory.js';
3
- import { StubEnvironmentGateway } from '../../tests/stubs/environment.stub.js';
4
- import { StubEmberReadDataGateway } from '../../tests/stubs/emberReadData.stub.js';
5
- import { StubEmberSessionTransportGateway } from '../../tests/stubs/emberSessionTransport.stub.js';
6
- import { EmberSessionRegistry } from '../../modules/ember-chat/usecases/emberSession/emberSessionRegistry.js';
7
- import { askEmber } from '../../modules/ember-chat/usecases/askEmber/askEmber.usecase.js';
8
- const PROJECT_PATH = '/projects/alpha';
9
- const FIXED_NOW = () => new Date('2026-05-28T10:00:00Z');
10
- function fixedReviewData() {
11
- const worstProject = ProjectStatsFactory.withReviews([
12
- ReviewStatsFactory.create({ mrNumber: 42, score: 3, blocking: 4, warnings: 1 }),
13
- ReviewStatsFactory.create({ mrNumber: 43, score: 4, blocking: 2, warnings: 0 }),
14
- ]);
15
- const readData = new StubEmberReadDataGateway();
16
- readData.setReviewScores(PROJECT_PATH, worstProject);
17
- return readData;
18
- }
19
- function buildRegistry(transport) {
20
- return new EmberSessionRegistry({ transport, now: FIXED_NOW, idleTimeoutMs: 60_000 });
21
- }
22
- function buildEnvironment(hasApiKey) {
23
- const environment = new StubEnvironmentGateway();
24
- environment.setHasAnthropicApiKey(hasApiKey);
25
- return environment;
26
- }
27
- function collectStream(subscribe) {
28
- return new Promise((resolve) => {
29
- let answer = '';
30
- const statuses = [];
31
- subscribe({
32
- onStatus: (state) => {
33
- statuses.push(state);
34
- },
35
- onChunk: (text) => {
36
- answer += text;
37
- },
38
- onDone: () => {
39
- resolve({ answer, statuses });
40
- },
41
- onError: () => {
42
- resolve({ answer, statuses });
43
- },
44
- });
45
- });
46
- }
47
- describe('Ask Ember about your reviews (acceptance, SPEC-189 Phase A)', () => {
48
- describe('Ember answers from review data with a working then idle status sequence', () => {
49
- it('ask about scores: the answer is grounded in the current review scores', async () => {
50
- const readData = fixedReviewData();
51
- const transport = new StubEmberSessionTransportGateway();
52
- transport.answerFromSystemPrompt();
53
- const result = await askEmber({ question: 'Quel projet a le pire score moyen cette semaine ?' }, {
54
- registry: buildRegistry(transport),
55
- environment: buildEnvironment(false),
56
- readData,
57
- projectPath: PROJECT_PATH,
58
- now: FIXED_NOW,
59
- });
60
- expect(result.status).toBe('streaming');
61
- if (result.status !== 'streaming') {
62
- return;
63
- }
64
- const { answer, statuses } = await collectStream(result.subscribe);
65
- // "42" reaches the answer only by traversing the production grounding path:
66
- // readData -> askEmber -> system prompt -> session. The stub echoes the prompt.
67
- expect(answer).toContain('42');
68
- expect(statuses[0]).toBe('working');
69
- expect(statuses.at(-1)).toBe('idle');
70
- });
71
- });
72
- describe('Ember requires no API key', () => {
73
- it('billing regression: declines to spawn when an Anthropic API key is present', async () => {
74
- const transport = new StubEmberSessionTransportGateway();
75
- transport.answerFromSystemPrompt();
76
- const result = await askEmber({ question: 'Quel projet a le pire score moyen cette semaine ?' }, {
77
- registry: buildRegistry(transport),
78
- environment: buildEnvironment(true),
79
- readData: fixedReviewData(),
80
- projectPath: PROJECT_PATH,
81
- now: FIXED_NOW,
82
- });
83
- expect(result.status).toBe('billing-regression-prevented');
84
- expect(transport.spawnCount).toBe(0);
85
- });
86
- });
87
- describe('within a session, consecutive questions reuse one Ember', () => {
88
- it('follow-up keeps context: a second question does not cold-start a new session', async () => {
89
- const transport = new StubEmberSessionTransportGateway();
90
- transport.answerFromSystemPrompt();
91
- const deps = {
92
- registry: buildRegistry(transport),
93
- environment: buildEnvironment(false),
94
- readData: fixedReviewData(),
95
- projectPath: PROJECT_PATH,
96
- now: FIXED_NOW,
97
- };
98
- const first = await askEmber({ question: 'Quel projet a le pire score moyen ?' }, deps);
99
- if (first.status === 'streaming') {
100
- await collectStream(first.subscribe);
101
- }
102
- const second = await askEmber({ question: 'Et le mois dernier ?' }, deps);
103
- if (second.status === 'streaming') {
104
- await collectStream(second.subscribe);
105
- }
106
- expect(transport.spawnCount).toBe(1);
107
- });
108
- });
109
- describe('when Ember cannot be reached, the chat reports unavailability', () => {
110
- it('assistant unreachable: returns unavailable when the transport fails to spawn', async () => {
111
- const transport = new StubEmberSessionTransportGateway();
112
- transport.failSpawn();
113
- const result = await askEmber({ question: 'Quel projet a le pire score moyen ?' }, {
114
- registry: buildRegistry(transport),
115
- environment: buildEnvironment(false),
116
- readData: fixedReviewData(),
117
- projectPath: PROJECT_PATH,
118
- now: FIXED_NOW,
119
- });
120
- expect(result.status).toBe('unavailable');
121
- });
122
- });
123
- });
124
- //# sourceMappingURL=189-ember-readonly-review-chat.acceptance.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"189-ember-readonly-review-chat.acceptance.test.js","sourceRoot":"","sources":["../../../src/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.ts"],"names":[],"mappings":"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"}
@@ -1,18 +0,0 @@
1
- import type { EmberSessionSpawnOptions, EmberSessionSpawnResult, EmberSessionTransportGateway } from '../../modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.js';
2
- type AnswerBuilder = (question: string, systemPrompt: string) => Promise<string>;
3
- export declare class StubEmberSessionTransportGateway implements EmberSessionTransportGateway {
4
- spawnCount: number;
5
- private shouldFail;
6
- private answerBuilder;
7
- failSpawn(): void;
8
- respondWith(builder: AnswerBuilder): void;
9
- /**
10
- * Makes the stub answer with the system prompt it was spawned with. The grounding
11
- * data lives in that prompt, so this proves the real path: readData → askEmber →
12
- * prompt → session, rather than the stub fabricating an answer of its own.
13
- */
14
- answerFromSystemPrompt(): void;
15
- spawn(options: EmberSessionSpawnOptions): EmberSessionSpawnResult;
16
- }
17
- export {};
18
- //# sourceMappingURL=emberSessionTransport.stub.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionTransport.stub.d.ts","sourceRoot":"","sources":["../../../src/tests/stubs/emberSessionTransport.stub.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,wBAAwB,EACxB,uBAAuB,EACvB,4BAA4B,EAC7B,MAAM,6EAA6E,CAAC;AAErF,KAAK,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAqDjF,qBAAa,gCAAiC,YAAW,4BAA4B;IACnF,UAAU,SAAK;IACf,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,aAAa,CAAgE;IAErF,SAAS,IAAI,IAAI;IAIjB,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAIzC;;;;OAIG;IACH,sBAAsB,IAAI,IAAI;IAI9B,KAAK,CAAC,OAAO,EAAE,wBAAwB,GAAG,uBAAuB;CAUlE"}
@@ -1,75 +0,0 @@
1
- class StubEmberSessionHandle {
2
- answerBuilder;
3
- systemPrompt;
4
- chunkHandler = null;
5
- doneHandler = null;
6
- errorHandler = null;
7
- alive = true;
8
- constructor(answerBuilder, systemPrompt) {
9
- this.answerBuilder = answerBuilder;
10
- this.systemPrompt = systemPrompt;
11
- }
12
- ask(question) {
13
- void this.deliver(question);
14
- }
15
- onChunk(handler) {
16
- this.chunkHandler = handler;
17
- }
18
- onDone(handler) {
19
- this.doneHandler = handler;
20
- }
21
- onError(handler) {
22
- this.errorHandler = handler;
23
- }
24
- isAlive() {
25
- return this.alive;
26
- }
27
- kill() {
28
- this.alive = false;
29
- }
30
- async deliver(question) {
31
- try {
32
- const answer = await this.answerBuilder(question, this.systemPrompt);
33
- const words = answer.split(' ');
34
- for (let index = 0; index < words.length; index += 1) {
35
- const fragment = index === 0 ? words[index] : ` ${words[index]}`;
36
- this.chunkHandler?.(fragment);
37
- }
38
- this.doneHandler?.();
39
- }
40
- catch (error) {
41
- const message = error instanceof Error ? error.message : 'stub-answer-failed';
42
- this.errorHandler?.(message);
43
- }
44
- }
45
- }
46
- export class StubEmberSessionTransportGateway {
47
- spawnCount = 0;
48
- shouldFail = false;
49
- answerBuilder = async (question) => `Réponse à : ${question}`;
50
- failSpawn() {
51
- this.shouldFail = true;
52
- }
53
- respondWith(builder) {
54
- this.answerBuilder = builder;
55
- }
56
- /**
57
- * Makes the stub answer with the system prompt it was spawned with. The grounding
58
- * data lives in that prompt, so this proves the real path: readData → askEmber →
59
- * prompt → session, rather than the stub fabricating an answer of its own.
60
- */
61
- answerFromSystemPrompt() {
62
- this.answerBuilder = async (_question, systemPrompt) => systemPrompt;
63
- }
64
- spawn(options) {
65
- if (this.shouldFail) {
66
- return { status: 'failed', reason: 'stub-spawn-failed' };
67
- }
68
- this.spawnCount += 1;
69
- return {
70
- status: 'spawned',
71
- handle: new StubEmberSessionHandle(this.answerBuilder, options.systemPrompt),
72
- };
73
- }
74
- }
75
- //# sourceMappingURL=emberSessionTransport.stub.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionTransport.stub.js","sourceRoot":"","sources":["../../../src/tests/stubs/emberSessionTransport.stub.ts"],"names":[],"mappings":"AAYA,MAAM,sBAAsB;IAOP;IACA;IAPX,YAAY,GAA6B,IAAI,CAAC;IAC9C,WAAW,GAA4B,IAAI,CAAC;IAC5C,YAAY,GAA6B,IAAI,CAAC;IAC9C,KAAK,GAAG,IAAI,CAAC;IAErB,YACmB,aAA4B,EAC5B,YAAoB;QADpB,kBAAa,GAAb,aAAa,CAAe;QAC5B,iBAAY,GAAZ,YAAY,CAAQ;IACpC,CAAC;IAEJ,GAAG,CAAC,QAAgB;QAClB,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,CAAC,OAA0B;QAChC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;IAC9B,CAAC;IAED,MAAM,CAAC,OAAyB;QAC9B,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;IAC7B,CAAC;IAED,OAAO,CAAC,OAA0B;QAChC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;IAC9B,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,QAAgB;QACpC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;YACrE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAChC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBACrD,MAAM,QAAQ,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACjE,IAAI,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,CAAC;YAChC,CAAC;YACD,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC;YAC9E,IAAI,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;CACF;AAED,MAAM,OAAO,gCAAgC;IAC3C,UAAU,GAAG,CAAC,CAAC;IACP,UAAU,GAAG,KAAK,CAAC;IACnB,aAAa,GAAkB,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,eAAe,QAAQ,EAAE,CAAC;IAErF,SAAS;QACP,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,WAAW,CAAC,OAAsB;QAChC,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACH,sBAAsB;QACpB,IAAI,CAAC,aAAa,GAAG,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC;IACvE,CAAC;IAED,KAAK,CAAC,OAAiC;QACrC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;QACrB,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,MAAM,EAAE,IAAI,sBAAsB,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,YAAY,CAAC;SAC7E,CAAC;IACJ,CAAC;CACF"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=emberSessionState.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionState.test.d.ts","sourceRoot":"","sources":["../../../../../../src/tests/units/modules/ember-chat/entities/emberSessionState.test.ts"],"names":[],"mappings":""}
@@ -1,42 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { createIdleEmberSessionState } from '../../../../../modules/ember-chat/entities/emberSession/emberSessionState.js';
3
- const IDLE_TIMEOUT_MS = 60_000;
4
- describe('EmberSessionState', () => {
5
- it('starts idle with no live process', () => {
6
- const state = createIdleEmberSessionState();
7
- expect(state.phase).toBe('idle');
8
- });
9
- it('becomes live when a question is asked', () => {
10
- const state = createIdleEmberSessionState().onQuestion(new Date('2026-05-28T10:00:00Z'));
11
- expect(state.phase).toBe('live');
12
- });
13
- it('stays live after an answer completes', () => {
14
- const state = createIdleEmberSessionState()
15
- .onQuestion(new Date('2026-05-28T10:00:00Z'))
16
- .onAnswerDone(new Date('2026-05-28T10:00:05Z'));
17
- expect(state.phase).toBe('live');
18
- });
19
- it('releases to idle when inactivity exceeds the timeout', () => {
20
- const state = createIdleEmberSessionState()
21
- .onQuestion(new Date('2026-05-28T10:00:00Z'))
22
- .onAnswerDone(new Date('2026-05-28T10:00:05Z'))
23
- .onIdleTick(new Date('2026-05-28T10:02:00Z'), IDLE_TIMEOUT_MS);
24
- expect(state.phase).toBe('idle');
25
- });
26
- it('stays live when inactivity is within the timeout', () => {
27
- const state = createIdleEmberSessionState()
28
- .onQuestion(new Date('2026-05-28T10:00:00Z'))
29
- .onAnswerDone(new Date('2026-05-28T10:00:05Z'))
30
- .onIdleTick(new Date('2026-05-28T10:00:30Z'), IDLE_TIMEOUT_MS);
31
- expect(state.phase).toBe('live');
32
- });
33
- it('reports needing a process when idle and a question arrives', () => {
34
- const idle = createIdleEmberSessionState();
35
- expect(idle.needsProcess()).toBe(true);
36
- });
37
- it('does not need a new process when already live', () => {
38
- const live = createIdleEmberSessionState().onQuestion(new Date('2026-05-28T10:00:00Z'));
39
- expect(live.needsProcess()).toBe(false);
40
- });
41
- });
42
- //# sourceMappingURL=emberSessionState.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionState.test.js","sourceRoot":"","sources":["../../../../../../src/tests/units/modules/ember-chat/entities/emberSessionState.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,2BAA2B,EAAE,MAAM,iEAAiE,CAAC;AAE9G,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,KAAK,GAAG,2BAA2B,EAAE,CAAC;QAE5C,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,KAAK,GAAG,2BAA2B,EAAE,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAEzF,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,KAAK,GAAG,2BAA2B,EAAE;aACxC,UAAU,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC;aAC5C,YAAY,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAElD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,KAAK,GAAG,2BAA2B,EAAE;aACxC,UAAU,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC;aAC5C,YAAY,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC;aAC9C,UAAU,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,EAAE,eAAe,CAAC,CAAC;QAEjE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,KAAK,GAAG,2BAA2B,EAAE;aACxC,UAAU,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC;aAC5C,YAAY,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC;aAC9C,UAAU,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,EAAE,eAAe,CAAC,CAAC;QAEjE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,IAAI,GAAG,2BAA2B,EAAE,CAAC;QAE3C,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,IAAI,GAAG,2BAA2B,EAAE,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAExF,MAAM,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=emberSessionRegistry.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionRegistry.test.d.ts","sourceRoot":"","sources":["../../../../../../src/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.ts"],"names":[],"mappings":""}
@@ -1,88 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { StubEmberSessionTransportGateway } from '../../../../../tests/stubs/emberSessionTransport.stub.js';
3
- import { EmberSessionRegistry } from '../../../../../modules/ember-chat/usecases/emberSession/emberSessionRegistry.js';
4
- const SYSTEM_PROMPT = 'you are ember';
5
- const PROJECT_PATH = '/projects/alpha';
6
- function drain(subscribe) {
7
- return new Promise((resolve) => {
8
- let answer = '';
9
- const statuses = [];
10
- subscribe({
11
- onStatus: (state) => statuses.push(state),
12
- onChunk: (text) => {
13
- answer += text;
14
- },
15
- onDone: () => resolve({ answer, statuses }),
16
- onError: () => resolve({ answer, statuses }),
17
- });
18
- });
19
- }
20
- describe('EmberSessionRegistry', () => {
21
- it('reuses one transport handle across consecutive questions', async () => {
22
- const transport = new StubEmberSessionTransportGateway();
23
- let clock = new Date('2026-05-28T10:00:00Z');
24
- const registry = new EmberSessionRegistry({
25
- transport,
26
- now: () => clock,
27
- idleTimeoutMs: 60_000,
28
- });
29
- const first = registry.ask({ question: 'q1', systemPrompt: SYSTEM_PROMPT, projectPath: PROJECT_PATH });
30
- if (first.status === 'streaming') {
31
- await drain(first.subscribe);
32
- }
33
- clock = new Date('2026-05-28T10:00:10Z');
34
- const second = registry.ask({ question: 'q2', systemPrompt: SYSTEM_PROMPT, projectPath: PROJECT_PATH });
35
- if (second.status === 'streaming') {
36
- await drain(second.subscribe);
37
- }
38
- expect(transport.spawnCount).toBe(1);
39
- });
40
- it('emits a working then idle status sequence for one question', async () => {
41
- const transport = new StubEmberSessionTransportGateway();
42
- const registry = new EmberSessionRegistry({
43
- transport,
44
- now: () => new Date('2026-05-28T10:00:00Z'),
45
- idleTimeoutMs: 60_000,
46
- });
47
- const result = registry.ask({ question: 'q', systemPrompt: SYSTEM_PROMPT, projectPath: PROJECT_PATH });
48
- expect(result.status).toBe('streaming');
49
- if (result.status !== 'streaming') {
50
- return;
51
- }
52
- const { statuses } = await drain(result.subscribe);
53
- expect(statuses[0]).toBe('working');
54
- expect(statuses.at(-1)).toBe('idle');
55
- });
56
- it('transparently revives with a fresh spawn after the idle timeout releases the session', async () => {
57
- const transport = new StubEmberSessionTransportGateway();
58
- let clock = new Date('2026-05-28T10:00:00Z');
59
- const registry = new EmberSessionRegistry({
60
- transport,
61
- now: () => clock,
62
- idleTimeoutMs: 60_000,
63
- });
64
- const first = registry.ask({ question: 'q1', systemPrompt: SYSTEM_PROMPT, projectPath: PROJECT_PATH });
65
- if (first.status === 'streaming') {
66
- await drain(first.subscribe);
67
- }
68
- clock = new Date('2026-05-28T10:05:00Z');
69
- registry.onIdle(clock);
70
- const second = registry.ask({ question: 'q2', systemPrompt: SYSTEM_PROMPT, projectPath: PROJECT_PATH });
71
- if (second.status === 'streaming') {
72
- await drain(second.subscribe);
73
- }
74
- expect(transport.spawnCount).toBe(2);
75
- });
76
- it('returns unavailable when the transport fails to spawn', () => {
77
- const transport = new StubEmberSessionTransportGateway();
78
- transport.failSpawn();
79
- const registry = new EmberSessionRegistry({
80
- transport,
81
- now: () => new Date('2026-05-28T10:00:00Z'),
82
- idleTimeoutMs: 60_000,
83
- });
84
- const result = registry.ask({ question: 'q', systemPrompt: SYSTEM_PROMPT, projectPath: PROJECT_PATH });
85
- expect(result.status).toBe('unavailable');
86
- });
87
- });
88
- //# sourceMappingURL=emberSessionRegistry.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionRegistry.test.js","sourceRoot":"","sources":["../../../../../../src/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.ts"],"names":[],"mappings":"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"}