reviewflow 3.30.0 → 3.32.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 (144) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/dashboard/index.html +35 -11
  3. package/dist/dashboard/styles.css +139 -5
  4. package/dist/frameworks/claude/claudeInvoker.d.ts +7 -0
  5. package/dist/frameworks/claude/claudeInvoker.d.ts.map +1 -1
  6. package/dist/frameworks/claude/claudeInvoker.js +1 -1
  7. package/dist/frameworks/claude/claudeInvoker.js.map +1 -1
  8. package/dist/main/routes.d.ts.map +1 -1
  9. package/dist/main/routes.js +9 -16
  10. package/dist/main/routes.js.map +1 -1
  11. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.gateway.d.ts +1 -1
  12. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.gateway.d.ts.map +1 -1
  13. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.guard.d.ts +1 -1
  14. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.d.ts +2 -0
  15. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.d.ts.map +1 -1
  16. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.js +1 -1
  17. package/dist/modules/claude-invocation/entities/claudeSession/claudeSession.schema.js.map +1 -1
  18. package/dist/modules/ember-chat/entities/emberAnswer/emberAnswerTransport.gateway.d.ts +24 -0
  19. package/dist/modules/ember-chat/entities/emberAnswer/emberAnswerTransport.gateway.d.ts.map +1 -0
  20. package/dist/modules/ember-chat/entities/emberAnswer/emberAnswerTransport.gateway.js +2 -0
  21. package/dist/modules/ember-chat/entities/emberAnswer/emberAnswerTransport.gateway.js.map +1 -0
  22. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.gateway.d.ts +8 -0
  23. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.gateway.d.ts.map +1 -0
  24. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.gateway.js +2 -0
  25. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.gateway.js.map +1 -0
  26. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.guard.d.ts +8 -0
  27. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.guard.d.ts.map +1 -0
  28. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.guard.js +4 -0
  29. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.guard.js.map +1 -0
  30. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.schema.d.ts +17 -0
  31. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.schema.d.ts.map +1 -0
  32. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.schema.js +11 -0
  33. package/dist/modules/ember-chat/entities/emberMemory/emberMemory.schema.js.map +1 -0
  34. package/dist/modules/ember-chat/interface-adapters/controllers/http/emberChat.routes.d.ts +4 -3
  35. package/dist/modules/ember-chat/interface-adapters/controllers/http/emberChat.routes.d.ts.map +1 -1
  36. package/dist/modules/ember-chat/interface-adapters/controllers/http/emberChat.routes.js +12 -4
  37. package/dist/modules/ember-chat/interface-adapters/controllers/http/emberChat.routes.js.map +1 -1
  38. package/dist/modules/ember-chat/interface-adapters/gateways/emberAnswerTransport.claude.gateway.d.ts +46 -0
  39. package/dist/modules/ember-chat/interface-adapters/gateways/emberAnswerTransport.claude.gateway.d.ts.map +1 -0
  40. package/dist/modules/ember-chat/interface-adapters/gateways/emberAnswerTransport.claude.gateway.js +176 -0
  41. package/dist/modules/ember-chat/interface-adapters/gateways/emberAnswerTransport.claude.gateway.js.map +1 -0
  42. package/dist/modules/ember-chat/interface-adapters/gateways/emberMemory.fileSystem.gateway.d.ts +22 -0
  43. package/dist/modules/ember-chat/interface-adapters/gateways/emberMemory.fileSystem.gateway.d.ts.map +1 -0
  44. package/dist/modules/ember-chat/interface-adapters/gateways/emberMemory.fileSystem.gateway.js +55 -0
  45. package/dist/modules/ember-chat/interface-adapters/gateways/emberMemory.fileSystem.gateway.js.map +1 -0
  46. package/dist/modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.d.ts +2 -1
  47. package/dist/modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.d.ts.map +1 -1
  48. package/dist/modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.js +8 -2
  49. package/dist/modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.js.map +1 -1
  50. package/dist/modules/ember-chat/interface-adapters/presenters/emberStatus.presenter.d.ts +1 -1
  51. package/dist/modules/ember-chat/interface-adapters/presenters/emberStatus.presenter.d.ts.map +1 -1
  52. package/dist/modules/ember-chat/services/emberSystemPrompt.d.ts +2 -0
  53. package/dist/modules/ember-chat/services/emberSystemPrompt.d.ts.map +1 -1
  54. package/dist/modules/ember-chat/services/emberSystemPrompt.js +87 -11
  55. package/dist/modules/ember-chat/services/emberSystemPrompt.js.map +1 -1
  56. package/dist/modules/ember-chat/usecases/askEmber/askEmber.usecase.d.ts +7 -4
  57. package/dist/modules/ember-chat/usecases/askEmber/askEmber.usecase.d.ts.map +1 -1
  58. package/dist/modules/ember-chat/usecases/askEmber/askEmber.usecase.js +90 -8
  59. package/dist/modules/ember-chat/usecases/askEmber/askEmber.usecase.js.map +1 -1
  60. package/dist/modules/ember-chat/usecases/askEmber/emberStream.d.ts +8 -0
  61. package/dist/modules/ember-chat/usecases/askEmber/emberStream.d.ts.map +1 -0
  62. package/dist/modules/ember-chat/usecases/askEmber/emberStream.js +2 -0
  63. package/dist/modules/ember-chat/usecases/askEmber/emberStream.js.map +1 -0
  64. package/dist/modules/ember-chat/usecases/clearEmberMemory/clearEmberMemory.usecase.d.ts +7 -0
  65. package/dist/modules/ember-chat/usecases/clearEmberMemory/clearEmberMemory.usecase.d.ts.map +1 -0
  66. package/dist/modules/ember-chat/usecases/clearEmberMemory/clearEmberMemory.usecase.js +4 -0
  67. package/dist/modules/ember-chat/usecases/clearEmberMemory/clearEmberMemory.usecase.js.map +1 -0
  68. package/dist/tests/acceptance/190-ember-live-answers-subscription.acceptance.test.d.ts +2 -0
  69. package/dist/tests/acceptance/190-ember-live-answers-subscription.acceptance.test.d.ts.map +1 -0
  70. package/dist/tests/acceptance/190-ember-live-answers-subscription.acceptance.test.js +165 -0
  71. package/dist/tests/acceptance/190-ember-live-answers-subscription.acceptance.test.js.map +1 -0
  72. package/dist/tests/acceptance/192-ember-ondemand-grounding-and-memory.acceptance.test.d.ts +2 -0
  73. package/dist/tests/acceptance/192-ember-ondemand-grounding-and-memory.acceptance.test.d.ts.map +1 -0
  74. package/dist/tests/acceptance/192-ember-ondemand-grounding-and-memory.acceptance.test.js +261 -0
  75. package/dist/tests/acceptance/192-ember-ondemand-grounding-and-memory.acceptance.test.js.map +1 -0
  76. package/dist/tests/factories/emberMemory.factory.d.ts +8 -0
  77. package/dist/tests/factories/emberMemory.factory.d.ts.map +1 -0
  78. package/dist/tests/factories/emberMemory.factory.js +19 -0
  79. package/dist/tests/factories/emberMemory.factory.js.map +1 -0
  80. package/dist/tests/stubs/emberAnswerTransport.stub.d.ts +21 -0
  81. package/dist/tests/stubs/emberAnswerTransport.stub.d.ts.map +1 -0
  82. package/dist/tests/stubs/emberAnswerTransport.stub.js +54 -0
  83. package/dist/tests/stubs/emberAnswerTransport.stub.js.map +1 -0
  84. package/dist/tests/stubs/emberMemory.stub.d.ts +25 -0
  85. package/dist/tests/stubs/emberMemory.stub.d.ts.map +1 -0
  86. package/dist/tests/stubs/emberMemory.stub.js +61 -0
  87. package/dist/tests/stubs/emberMemory.stub.js.map +1 -0
  88. package/dist/tests/units/modules/ember-chat/controllers/emberChat.routes.test.js +35 -14
  89. package/dist/tests/units/modules/ember-chat/controllers/emberChat.routes.test.js.map +1 -1
  90. package/dist/tests/units/modules/ember-chat/entities/emberMemory.guard.test.d.ts +2 -0
  91. package/dist/tests/units/modules/ember-chat/entities/emberMemory.guard.test.d.ts.map +1 -0
  92. package/dist/tests/units/modules/ember-chat/entities/emberMemory.guard.test.js +51 -0
  93. package/dist/tests/units/modules/ember-chat/entities/emberMemory.guard.test.js.map +1 -0
  94. package/dist/tests/units/modules/ember-chat/gateways/emberMemory.fileSystem.gateway.test.d.ts +2 -0
  95. package/dist/tests/units/modules/ember-chat/gateways/emberMemory.fileSystem.gateway.test.d.ts.map +1 -0
  96. package/dist/tests/units/modules/ember-chat/gateways/emberMemory.fileSystem.gateway.test.js +82 -0
  97. package/dist/tests/units/modules/ember-chat/gateways/emberMemory.fileSystem.gateway.test.js.map +1 -0
  98. package/dist/tests/units/modules/ember-chat/gateways/emberStreamJson.parser.test.js +13 -0
  99. package/dist/tests/units/modules/ember-chat/gateways/emberStreamJson.parser.test.js.map +1 -1
  100. package/dist/tests/units/modules/ember-chat/services/emberSystemPrompt.test.js +93 -2
  101. package/dist/tests/units/modules/ember-chat/services/emberSystemPrompt.test.js.map +1 -1
  102. package/dist/tests/units/modules/ember-chat/usecases/askEmber.usecase.test.js +108 -20
  103. package/dist/tests/units/modules/ember-chat/usecases/askEmber.usecase.test.js.map +1 -1
  104. package/dist/tests/units/modules/ember-chat/usecases/clearEmberMemory.usecase.test.d.ts +2 -0
  105. package/dist/tests/units/modules/ember-chat/usecases/clearEmberMemory.usecase.test.d.ts.map +1 -0
  106. package/dist/tests/units/modules/ember-chat/usecases/clearEmberMemory.usecase.test.js +14 -0
  107. package/dist/tests/units/modules/ember-chat/usecases/clearEmberMemory.usecase.test.js.map +1 -0
  108. package/package.json +1 -1
  109. package/dist/modules/ember-chat/entities/emberSession/emberSession.schema.d.ts +0 -7
  110. package/dist/modules/ember-chat/entities/emberSession/emberSession.schema.d.ts.map +0 -1
  111. package/dist/modules/ember-chat/entities/emberSession/emberSession.schema.js +0 -3
  112. package/dist/modules/ember-chat/entities/emberSession/emberSession.schema.js.map +0 -1
  113. package/dist/modules/ember-chat/entities/emberSession/emberSessionState.d.ts +0 -13
  114. package/dist/modules/ember-chat/entities/emberSession/emberSessionState.d.ts.map +0 -1
  115. package/dist/modules/ember-chat/entities/emberSession/emberSessionState.js +0 -35
  116. package/dist/modules/ember-chat/entities/emberSession/emberSessionState.js.map +0 -1
  117. package/dist/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.d.ts +0 -26
  118. package/dist/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.d.ts.map +0 -1
  119. package/dist/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.js +0 -2
  120. package/dist/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.js.map +0 -1
  121. package/dist/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.d.ts +0 -13
  122. package/dist/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.d.ts.map +0 -1
  123. package/dist/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.js +0 -130
  124. package/dist/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.js.map +0 -1
  125. package/dist/modules/ember-chat/usecases/emberSession/emberSessionRegistry.d.ts +0 -36
  126. package/dist/modules/ember-chat/usecases/emberSession/emberSessionRegistry.d.ts.map +0 -1
  127. package/dist/modules/ember-chat/usecases/emberSession/emberSessionRegistry.js +0 -59
  128. package/dist/modules/ember-chat/usecases/emberSession/emberSessionRegistry.js.map +0 -1
  129. package/dist/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.d.ts +0 -2
  130. package/dist/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.d.ts.map +0 -1
  131. package/dist/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.js +0 -124
  132. package/dist/tests/acceptance/189-ember-readonly-review-chat.acceptance.test.js.map +0 -1
  133. package/dist/tests/stubs/emberSessionTransport.stub.d.ts +0 -18
  134. package/dist/tests/stubs/emberSessionTransport.stub.d.ts.map +0 -1
  135. package/dist/tests/stubs/emberSessionTransport.stub.js +0 -75
  136. package/dist/tests/stubs/emberSessionTransport.stub.js.map +0 -1
  137. package/dist/tests/units/modules/ember-chat/entities/emberSessionState.test.d.ts +0 -2
  138. package/dist/tests/units/modules/ember-chat/entities/emberSessionState.test.d.ts.map +0 -1
  139. package/dist/tests/units/modules/ember-chat/entities/emberSessionState.test.js +0 -42
  140. package/dist/tests/units/modules/ember-chat/entities/emberSessionState.test.js.map +0 -1
  141. package/dist/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.d.ts +0 -2
  142. package/dist/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.d.ts.map +0 -1
  143. package/dist/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.js +0 -88
  144. package/dist/tests/units/modules/ember-chat/usecases/emberSessionRegistry.test.js.map +0 -1
@@ -1,35 +0,0 @@
1
- export class EmberSessionState {
2
- props;
3
- constructor(props) {
4
- this.props = props;
5
- }
6
- static idle() {
7
- return new EmberSessionState({ phase: 'idle', lastActivityAt: null });
8
- }
9
- get phase() {
10
- return this.props.phase;
11
- }
12
- needsProcess() {
13
- return this.props.phase === 'idle';
14
- }
15
- onQuestion(now) {
16
- return new EmberSessionState({ phase: 'live', lastActivityAt: now });
17
- }
18
- onAnswerDone(now) {
19
- return new EmberSessionState({ phase: 'live', lastActivityAt: now });
20
- }
21
- onIdleTick(now, timeoutMs) {
22
- if (this.props.phase === 'idle' || this.props.lastActivityAt === null) {
23
- return this;
24
- }
25
- const inactiveMs = now.getTime() - this.props.lastActivityAt.getTime();
26
- if (inactiveMs >= timeoutMs) {
27
- return EmberSessionState.idle();
28
- }
29
- return this;
30
- }
31
- }
32
- export function createIdleEmberSessionState() {
33
- return EmberSessionState.idle();
34
- }
35
- //# sourceMappingURL=emberSessionState.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionState.js","sourceRoot":"","sources":["../../../../../src/modules/ember-chat/entities/emberSession/emberSessionState.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,iBAAiB;IACS;IAArC,YAAqC,KAA6B;QAA7B,UAAK,GAAL,KAAK,CAAwB;IAAG,CAAC;IAEtE,MAAM,CAAC,IAAI;QACT,OAAO,IAAI,iBAAiB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAC1B,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM,CAAC;IACrC,CAAC;IAED,UAAU,CAAC,GAAS;QAClB,OAAO,IAAI,iBAAiB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,YAAY,CAAC,GAAS;QACpB,OAAO,IAAI,iBAAiB,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,UAAU,CAAC,GAAS,EAAE,SAAiB;QACrC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,cAAc,KAAK,IAAI,EAAE,CAAC;YACtE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;QACvE,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC;YAC5B,OAAO,iBAAiB,CAAC,IAAI,EAAE,CAAC;QAClC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,MAAM,UAAU,2BAA2B;IACzC,OAAO,iBAAiB,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC"}
@@ -1,26 +0,0 @@
1
- export type EmberChunkHandler = (text: string) => void;
2
- export type EmberDoneHandler = () => void;
3
- export type EmberErrorHandler = (message: string) => void;
4
- export interface EmberSessionHandle {
5
- ask(question: string): void;
6
- onChunk(handler: EmberChunkHandler): void;
7
- onDone(handler: EmberDoneHandler): void;
8
- onError(handler: EmberErrorHandler): void;
9
- isAlive(): boolean;
10
- kill(): void;
11
- }
12
- export interface EmberSessionSpawnOptions {
13
- systemPrompt: string;
14
- projectPath: string;
15
- }
16
- export type EmberSessionSpawnResult = {
17
- status: 'spawned';
18
- handle: EmberSessionHandle;
19
- } | {
20
- status: 'failed';
21
- reason: string;
22
- };
23
- export interface EmberSessionTransportGateway {
24
- spawn(options: EmberSessionSpawnOptions): EmberSessionSpawnResult;
25
- }
26
- //# sourceMappingURL=emberSessionTransport.gateway.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionTransport.gateway.d.ts","sourceRoot":"","sources":["../../../../../src/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AACvD,MAAM,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC;AAC1C,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAE1D,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC1C,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACxC,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC1C,OAAO,IAAI,OAAO,CAAC;IACnB,IAAI,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GACjD;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzC,MAAM,WAAW,4BAA4B;IAC3C,KAAK,CAAC,OAAO,EAAE,wBAAwB,GAAG,uBAAuB,CAAC;CACnE"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=emberSessionTransport.gateway.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionTransport.gateway.js","sourceRoot":"","sources":["../../../../../src/modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.ts"],"names":[],"mappings":""}
@@ -1,13 +0,0 @@
1
- import type { EmberSessionSpawnOptions, EmberSessionSpawnResult, EmberSessionTransportGateway } from '../../../../modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.js';
2
- export interface EmberSessionTransportClaudeGatewayOptions {
3
- claudePath: string;
4
- mcpConfigJson: string;
5
- allowedTools: string;
6
- model: string;
7
- }
8
- export declare class EmberSessionTransportClaudeGateway implements EmberSessionTransportGateway {
9
- private readonly options;
10
- constructor(options: EmberSessionTransportClaudeGatewayOptions);
11
- spawn(options: EmberSessionSpawnOptions): EmberSessionSpawnResult;
12
- }
13
- //# sourceMappingURL=emberSessionTransport.claude.gateway.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionTransport.claude.gateway.d.ts","sourceRoot":"","sources":["../../../../../src/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAKV,wBAAwB,EACxB,uBAAuB,EACvB,4BAA4B,EAC7B,MAAM,6EAA6E,CAAC;AAkGrF,MAAM,WAAW,yCAAyC;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,kCAAmC,YAAW,4BAA4B;IACzE,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,yCAAyC;IAE/E,KAAK,CAAC,OAAO,EAAE,wBAAwB,GAAG,uBAAuB;CAgClE"}
@@ -1,130 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
- import { splitLines } from '../../../../modules/setup-wizard/interface-adapters/gateways/setupProcess.childProcess.gateway.js';
3
- import { parseStreamJsonEvent, extractText, isTurnComplete, } from '../../../../modules/ember-chat/interface-adapters/gateways/emberStreamJson.parser.js';
4
- /**
5
- * HUMBLE GLUE — NOT unit-tested. The conversational transport over the `claude`
6
- * CLI is the one unverified mechanism in SPEC-189 (plan §12.1). Every layer above
7
- * it (state machine, registry, usecase, presenter, routes, client) is unit-tested
8
- * against the stub; this file is the swappable real implementation, validated by
9
- * acceptance/manual only.
10
- *
11
- * Most plausible CLI shape: ONE long-lived child running claude in interactive
12
- * streaming-JSON mode (`--input-format stream-json --output-format stream-json`),
13
- * so consecutive questions are written on stdin as user messages and the answer
14
- * is streamed back as assistant text deltas on stdout — keeping one resumable
15
- * conversational thread per process. Grounding is injected into the appended
16
- * system prompt (the review data is read through the typed EmberReadDataGateway
17
- * in askEmber), so the session needs NO tools and gets none. No API key: relies
18
- * on the operator's Claude login (subscription OAuth), like the bg dispatch path.
19
- *
20
- * MANUAL VERIFICATION REQUIRED: confirm the exact streaming-JSON event framing
21
- * (assistant text delta vs. message_stop) and that interactive stream-json input
22
- * keeps the thread alive across turns. Adjust extractText / isTurnComplete below
23
- * once verified against a live `claude` build.
24
- */
25
- class ClaudeEmberSessionHandle {
26
- child;
27
- chunkHandler = null;
28
- doneHandler = null;
29
- errorHandler = null;
30
- buffer = '';
31
- alive = true;
32
- constructor(child) {
33
- this.child = child;
34
- this.child.stdout.setEncoding('utf-8');
35
- this.child.stdout.on('data', (chunk) => {
36
- this.consume(chunk);
37
- });
38
- this.child.on('close', () => {
39
- this.alive = false;
40
- this.errorHandler?.('ember-session-closed');
41
- });
42
- this.child.on('error', () => {
43
- this.alive = false;
44
- this.errorHandler?.('ember-session-error');
45
- });
46
- }
47
- ask(question) {
48
- if (!this.child.stdin.writable) {
49
- this.errorHandler?.('ember-session-not-writable');
50
- return;
51
- }
52
- const userMessage = {
53
- type: 'user',
54
- message: { role: 'user', content: question },
55
- };
56
- this.child.stdin.write(`${JSON.stringify(userMessage)}\n`);
57
- }
58
- onChunk(handler) {
59
- this.chunkHandler = handler;
60
- }
61
- onDone(handler) {
62
- this.doneHandler = handler;
63
- }
64
- onError(handler) {
65
- this.errorHandler = handler;
66
- }
67
- isAlive() {
68
- return this.alive;
69
- }
70
- kill() {
71
- this.alive = false;
72
- this.child.kill();
73
- }
74
- consume(chunk) {
75
- const { lines, rest } = splitLines(this.buffer, chunk);
76
- this.buffer = rest;
77
- for (const line of lines) {
78
- const event = parseStreamJsonEvent(line);
79
- if (event === null) {
80
- continue;
81
- }
82
- const text = extractText(event);
83
- if (text !== null) {
84
- this.chunkHandler?.(text);
85
- }
86
- if (isTurnComplete(event)) {
87
- this.doneHandler?.();
88
- }
89
- }
90
- }
91
- }
92
- export class EmberSessionTransportClaudeGateway {
93
- options;
94
- constructor(options) {
95
- this.options = options;
96
- }
97
- spawn(options) {
98
- const args = [
99
- '--input-format',
100
- 'stream-json',
101
- '--output-format',
102
- 'stream-json',
103
- '--verbose',
104
- '--model',
105
- this.options.model,
106
- '--permission-mode',
107
- 'default',
108
- '--append-system-prompt',
109
- options.systemPrompt,
110
- '--mcp-config',
111
- this.options.mcpConfigJson,
112
- '--strict-mcp-config',
113
- '--allowedTools',
114
- this.options.allowedTools,
115
- ];
116
- try {
117
- const child = spawn(this.options.claudePath, args, {
118
- cwd: options.projectPath,
119
- stdio: ['pipe', 'pipe', 'pipe'],
120
- env: { ...process.env },
121
- });
122
- return { status: 'spawned', handle: new ClaudeEmberSessionHandle(child) };
123
- }
124
- catch (error) {
125
- const reason = error instanceof Error ? error.message : 'spawn-failed';
126
- return { status: 'failed', reason };
127
- }
128
- }
129
- }
130
- //# sourceMappingURL=emberSessionTransport.claude.gateway.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionTransport.claude.gateway.js","sourceRoot":"","sources":["../../../../../src/modules/ember-chat/interface-adapters/gateways/emberSessionTransport.claude.gateway.ts"],"names":[],"mappings":"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"}
@@ -1,36 +0,0 @@
1
- import type { EmberSessionTransportGateway } from '../../../../modules/ember-chat/entities/emberSession/emberSessionTransport.gateway.js';
2
- export type EmberStatus = 'working' | 'idle' | 'error';
3
- export interface EmberStreamSubscriber {
4
- onStatus: (status: EmberStatus) => void;
5
- onChunk: (text: string) => void;
6
- onDone: () => void;
7
- onError: (message: string) => void;
8
- }
9
- export type EmberAskResult = {
10
- status: 'streaming';
11
- subscribe: (subscriber: EmberStreamSubscriber) => void;
12
- } | {
13
- status: 'unavailable';
14
- reason: string;
15
- };
16
- export interface EmberAskRequest {
17
- question: string;
18
- systemPrompt: string;
19
- projectPath: string;
20
- }
21
- export interface EmberSessionRegistryDependencies {
22
- transport: EmberSessionTransportGateway;
23
- now: () => Date;
24
- idleTimeoutMs: number;
25
- }
26
- export declare class EmberSessionRegistry {
27
- private readonly dependencies;
28
- private handle;
29
- private state;
30
- constructor(dependencies: EmberSessionRegistryDependencies);
31
- ask(request: EmberAskRequest): EmberAskResult;
32
- onIdle(now: Date): void;
33
- private ensureLive;
34
- private release;
35
- }
36
- //# sourceMappingURL=emberSessionRegistry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionRegistry.d.ts","sourceRoot":"","sources":["../../../../../src/modules/ember-chat/usecases/emberSession/emberSessionRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,4BAA4B,EAC7B,MAAM,6EAA6E,CAAC;AAIrF,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEvD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,CAAC,UAAU,EAAE,qBAAqB,KAAK,IAAI,CAAA;CAAE,GAC/E;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gCAAgC;IAC/C,SAAS,EAAE,4BAA4B,CAAC;IACxC,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,oBAAoB;IAInB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAHzC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,KAAK,CAAoD;gBAEpC,YAAY,EAAE,gCAAgC;IAE3E,GAAG,CAAC,OAAO,EAAE,eAAe,GAAG,cAAc;IA2B7C,MAAM,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI;IAQvB,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,OAAO;CAMhB"}
@@ -1,59 +0,0 @@
1
- import { createIdleEmberSessionState } from '../../../../modules/ember-chat/entities/emberSession/emberSessionState.js';
2
- export class EmberSessionRegistry {
3
- dependencies;
4
- handle = null;
5
- state = createIdleEmberSessionState();
6
- constructor(dependencies) {
7
- this.dependencies = dependencies;
8
- }
9
- ask(request) {
10
- const handle = this.ensureLive(request.systemPrompt, request.projectPath);
11
- if (handle === null) {
12
- return { status: 'unavailable', reason: 'spawn-failed' };
13
- }
14
- this.state = this.state.onQuestion(this.dependencies.now());
15
- return {
16
- status: 'streaming',
17
- subscribe: (subscriber) => {
18
- subscriber.onStatus('working');
19
- handle.onChunk((text) => subscriber.onChunk(text));
20
- handle.onError((message) => {
21
- subscriber.onStatus('error');
22
- subscriber.onError(message);
23
- });
24
- handle.onDone(() => {
25
- this.state = this.state.onAnswerDone(this.dependencies.now());
26
- subscriber.onStatus('idle');
27
- subscriber.onDone();
28
- });
29
- handle.ask(request.question);
30
- },
31
- };
32
- }
33
- onIdle(now) {
34
- const next = this.state.onIdleTick(now, this.dependencies.idleTimeoutMs);
35
- if (next.phase === 'idle' && this.state.phase === 'live') {
36
- this.release();
37
- }
38
- this.state = next;
39
- }
40
- ensureLive(systemPrompt, projectPath) {
41
- if (this.handle?.isAlive() === true && !this.state.needsProcess()) {
42
- return this.handle;
43
- }
44
- const result = this.dependencies.transport.spawn({ systemPrompt, projectPath });
45
- if (result.status === 'failed') {
46
- this.handle = null;
47
- return null;
48
- }
49
- this.handle = result.handle;
50
- return this.handle;
51
- }
52
- release() {
53
- if (this.handle !== null) {
54
- this.handle.kill();
55
- this.handle = null;
56
- }
57
- }
58
- }
59
- //# sourceMappingURL=emberSessionRegistry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"emberSessionRegistry.js","sourceRoot":"","sources":["../../../../../src/modules/ember-chat/usecases/emberSession/emberSessionRegistry.ts"],"names":[],"mappings":"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"}
@@ -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