@adhdev/daemon-core 0.6.55 → 0.6.56

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.
@@ -2638,7 +2638,7 @@ export class DevServer {
2638
2638
  lines.push('| Function | Input | Return |');
2639
2639
  lines.push('|---|---|---|');
2640
2640
  lines.push('| `parseOutput` | `{ buffer, rawBuffer, recentBuffer, screenText, messages, partialResponse }` | `{ id, status, title, messages, activeModal }` |');
2641
- lines.push('| `detectStatus` | `{ tail }` | `idle`, `generating`, `waiting_approval`, or `error` |');
2641
+ lines.push('| `detectStatus` | `{ tail, screenText, rawBuffer }` | `idle`, `generating`, `waiting_approval`, or `error` |');
2642
2642
  lines.push('| `parseApproval` | `{ buffer, rawBuffer, tail }` | `{ message, buttons }` or `null` |');
2643
2643
  lines.push('');
2644
2644
 
@@ -2652,6 +2652,7 @@ export class DevServer {
2652
2652
  lines.push('7. Use `rawBuffer` only when ANSI/control-sequence artifacts matter. Do not depend on raw escape noise unless necessary.');
2653
2653
  lines.push('8. Keep exports compatible with the existing `scripts.js` router (`module.exports = function ...`).');
2654
2654
  lines.push('9. Do not rewrite unrelated provider config. Only touch the scripts needed for this task unless a tiny supporting change is required.');
2655
+ lines.push('10. When the verification API returns `instanceId`, keep using that exact instance for follow-up `send`, `resolve`, `raw`, and `stop` calls. Do not assume type-only routing is safe if multiple sessions exist.');
2655
2656
  lines.push('');
2656
2657
 
2657
2658
  lines.push('## Task');
@@ -2674,25 +2675,38 @@ export class DevServer {
2674
2675
  lines.push(`curl -sS http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/status`);
2675
2676
  lines.push('```');
2676
2677
  lines.push('');
2677
- lines.push('### 3. Send a rich test prompt');
2678
+ lines.push('Extract the current `instanceId` from the launch or status response and keep using it below.');
2679
+ lines.push('');
2680
+ lines.push('### 3. Send a realistic approval-triggering prompt');
2678
2681
  lines.push('```bash');
2679
2682
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/send \\`);
2680
2683
  lines.push(' -H "Content-Type: application/json" \\');
2681
- lines.push(` -d '{"type":"${type}","text":"Write a short python snippet, include a markdown table, and briefly explain what you did."}'`);
2684
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","text":"Create a file at tmp/adhdev_provider_fix_test.py that prints the current working directory and the squares of 1 through 5, then run python3 tmp/adhdev_provider_fix_test.py and tell me the exact output."}'`);
2682
2685
  lines.push('```');
2683
2686
  lines.push('');
2684
- lines.push('### 4. If approval appears, resolve it');
2687
+ lines.push('### 4. If approval appears, resolve it until the CLI reaches idle');
2685
2688
  lines.push('```bash');
2686
2689
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/resolve \\`);
2687
2690
  lines.push(' -H "Content-Type: application/json" \\');
2688
- lines.push(` -d '{"type":"${type}","buttonIndex":0}'`);
2691
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","buttonIndex":0}'`);
2692
+ lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/raw \\`);
2693
+ lines.push(' -H "Content-Type: application/json" \\');
2694
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>","keys":"1"}'`);
2689
2695
  lines.push('```');
2690
2696
  lines.push('');
2691
- lines.push('### 5. Stop the CLI when finished');
2697
+ lines.push('Use `resolve` when the parsed modal buttons are correct. Use `raw` when the CLI expects a literal keystroke like `1`, `y`, or Enter. Repeat until idle.');
2698
+ lines.push('');
2699
+ lines.push('### 5. Verify the side effects outside the CLI');
2700
+ lines.push('```bash');
2701
+ lines.push('test -f tmp/adhdev_provider_fix_test.py');
2702
+ lines.push('python3 tmp/adhdev_provider_fix_test.py');
2703
+ lines.push('```');
2704
+ lines.push('');
2705
+ lines.push('### 6. Stop the CLI when finished');
2692
2706
  lines.push('```bash');
2693
2707
  lines.push(`curl -sS -X POST http://127.0.0.1:${DEV_SERVER_PORT}/api/cli/stop \\`);
2694
2708
  lines.push(' -H "Content-Type: application/json" \\');
2695
- lines.push(` -d '{"type":"${type}"}'`);
2709
+ lines.push(` -d '{"type":"${type}","instanceId":"<INSTANCE_ID>"}'`);
2696
2710
  lines.push('```');
2697
2711
  lines.push('');
2698
2712
 
@@ -2701,7 +2715,9 @@ export class DevServer {
2701
2715
  lines.push('2. Confirm `parseOutput` produces a stable transcript without duplicating past turns when the PTY redraws.');
2702
2716
  lines.push('3. Confirm the latest assistant message streams through `partialResponse` while generation is in progress.');
2703
2717
  lines.push('4. Confirm approval parsing returns meaningful button labels when the CLI requests permission.');
2704
- lines.push('5. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.');
2718
+ lines.push('5. Confirm the Python file was actually created and executed, not just described in chat text.');
2719
+ lines.push('6. Confirm the final assistant transcript includes the exact Python output, including the working directory line and the five square numbers.');
2720
+ lines.push('7. Re-run the debug endpoints after edits. Do NOT finish until the parsed result looks correct.');
2705
2721
  lines.push('');
2706
2722
 
2707
2723
  if (userComment) {
@@ -2827,6 +2843,17 @@ export class DevServer {
2827
2843
  this.json(res, 200, { instances: result, count: result.length });
2828
2844
  }
2829
2845
 
2846
+ private findCliTarget(type?: string, instanceId?: string): any | null {
2847
+ if (!this.instanceManager) return null;
2848
+ const cliStates = this.instanceManager
2849
+ .collectAllStates()
2850
+ .filter(s => s.category === 'cli' || s.category === 'acp');
2851
+ if (instanceId) return cliStates.find(s => s.instanceId === instanceId) || null;
2852
+ if (!type) return cliStates[cliStates.length - 1] || null;
2853
+ const matches = cliStates.filter(s => s.type === type);
2854
+ return matches[matches.length - 1] || null;
2855
+ }
2856
+
2830
2857
  /** POST /api/cli/launch — launch a CLI agent { type, workingDir?, args? } */
2831
2858
  private async handleCliLaunch(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
2832
2859
  if (!this.cliManager) {
@@ -2860,12 +2887,7 @@ export class DevServer {
2860
2887
  return;
2861
2888
  }
2862
2889
 
2863
- // Find the CLI instance by type or instanceId
2864
- const allStates = this.instanceManager.collectAllStates();
2865
- const target = allStates.find(s =>
2866
- (s.category === 'cli' || s.category === 'acp') &&
2867
- (instanceId ? s.instanceId === instanceId : s.type === type)
2868
- );
2890
+ const target = this.findCliTarget(type, instanceId);
2869
2891
  if (!target) {
2870
2892
  this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
2871
2893
  return;
@@ -2888,11 +2910,7 @@ export class DevServer {
2888
2910
  const body = await this.readBody(req);
2889
2911
  const { type, instanceId } = body;
2890
2912
 
2891
- const allStates = this.instanceManager.collectAllStates();
2892
- const target = allStates.find(s =>
2893
- (s.category === 'cli' || s.category === 'acp') &&
2894
- (instanceId ? s.instanceId === instanceId : s.type === type)
2895
- );
2913
+ const target = this.findCliTarget(type, instanceId);
2896
2914
  if (!target) {
2897
2915
  this.json(res, 404, { error: `No running instance found for: ${type || instanceId}` });
2898
2916
  return;
@@ -2952,12 +2970,9 @@ export class DevServer {
2952
2970
  return;
2953
2971
  }
2954
2972
 
2955
- // Find the matching CLI instance
2956
- const allStates = this.instanceManager.collectAllStates();
2957
- const target = allStates.find(s =>
2958
- (s.category === 'cli' || s.category === 'acp') && s.type === type
2959
- );
2973
+ const target = this.findCliTarget(type);
2960
2974
  if (!target) {
2975
+ const allStates = this.instanceManager.collectAllStates();
2961
2976
  this.json(res, 404, { error: `No running instance for: ${type}`, available: allStates.filter(s => s.category === 'cli' || s.category === 'acp').map(s => s.type) });
2962
2977
  return;
2963
2978
  }
@@ -3010,19 +3025,28 @@ export class DevServer {
3010
3025
  this.json(res, 503, { error: 'CliManager not available' });
3011
3026
  return;
3012
3027
  }
3013
- // Find adapter from cliManager.adapters map
3014
- let adapter: any = null;
3015
- for (const [, a] of this.cliManager.adapters) {
3016
- if (type && (a as any).cliType === type) { adapter = a; break; }
3028
+ if (!this.instanceManager) {
3029
+ this.json(res, 503, { error: 'InstanceManager not available' });
3030
+ return;
3017
3031
  }
3018
- if (!adapter) {
3032
+
3033
+ const target = this.findCliTarget(type, instanceId);
3034
+ if (!target) {
3019
3035
  this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
3020
3036
  return;
3021
3037
  }
3038
+
3039
+ const instance = this.instanceManager.getInstance(target.instanceId) as any;
3040
+ const adapter = instance?.getAdapter?.() || instance?.adapter;
3041
+ if (!adapter) {
3042
+ this.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
3043
+ return;
3044
+ }
3045
+
3022
3046
  try {
3023
3047
  if (typeof adapter.resolveModal === 'function') {
3024
3048
  adapter.resolveModal(buttonIndex);
3025
- this.json(res, 200, { resolved: true, type, buttonIndex });
3049
+ this.json(res, 200, { resolved: true, type: target.type, instanceId: target.instanceId, buttonIndex });
3026
3050
  } else {
3027
3051
  this.json(res, 400, { error: 'resolveModal not available on this adapter' });
3028
3052
  }
@@ -3044,18 +3068,28 @@ export class DevServer {
3044
3068
  this.json(res, 503, { error: 'CliManager not available' });
3045
3069
  return;
3046
3070
  }
3047
- let adapter: any = null;
3048
- for (const [, a] of this.cliManager.adapters) {
3049
- if (type && (a as any).cliType === type) { adapter = a; break; }
3071
+ if (!this.instanceManager) {
3072
+ this.json(res, 503, { error: 'InstanceManager not available' });
3073
+ return;
3074
+ }
3075
+
3076
+ const target = this.findCliTarget(type, instanceId);
3077
+ if (!target) {
3078
+ this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
3079
+ return;
3050
3080
  }
3081
+
3082
+ const instance = this.instanceManager.getInstance(target.instanceId) as any;
3083
+ const adapter = instance?.getAdapter?.() || instance?.adapter;
3051
3084
  if (!adapter) {
3052
- this.json(res, 404, { error: `No running adapter for: ${type || instanceId}` });
3085
+ this.json(res, 404, { error: `Adapter not found for instance: ${target.instanceId}` });
3053
3086
  return;
3054
3087
  }
3088
+
3055
3089
  try {
3056
3090
  if (typeof adapter.writeRaw === 'function') {
3057
3091
  adapter.writeRaw(keys);
3058
- this.json(res, 200, { sent: true, type, keysLength: keys.length });
3092
+ this.json(res, 200, { sent: true, type: target.type, instanceId: target.instanceId, keysLength: keys.length });
3059
3093
  } else {
3060
3094
  this.json(res, 400, { error: 'writeRaw not available on this adapter' });
3061
3095
  }
@@ -103,7 +103,8 @@ export class CliProviderInstance implements ProviderInstance {
103
103
 
104
104
  // generating during partial response add
105
105
  const partial = this.adapter.getPartialResponse();
106
- if (adapterStatus.status === 'generating' && partial) {
106
+ const shouldAppendRawPartial = !parsedStatus;
107
+ if (shouldAppendRawPartial && adapterStatus.status === 'generating' && partial) {
107
108
  const cleaned = partial.trim();
108
109
  if (cleaned && cleaned !== '(generating...)') {
109
110
  recentMessages.push({