@gajae-code/coding-agent 0.18.1 → 0.18.6

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 (128) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/dist/types/cli/stats-cli.d.ts +0 -5
  3. package/dist/types/cli-commands.d.ts +10 -0
  4. package/dist/types/cli-ordinary.d.ts +13 -0
  5. package/dist/types/cli.d.ts +12 -3
  6. package/dist/types/commands/contribution-prep.d.ts +0 -3
  7. package/dist/types/commands/sdk.d.ts +3 -0
  8. package/dist/types/commands/update.d.ts +1 -0
  9. package/dist/types/config/autorouting-tier-map.d.ts +29 -2
  10. package/dist/types/config/model-profile-activation.d.ts +19 -0
  11. package/dist/types/config/model-registry.d.ts +16 -1
  12. package/dist/types/coordinator-mcp/session-reaper.d.ts +5 -0
  13. package/dist/types/edit/modes/replace.d.ts +3 -3
  14. package/dist/types/edit/streaming.d.ts +2 -2
  15. package/dist/types/exa/mcp-client.d.ts +1 -5
  16. package/dist/types/exec/bash-shell-guardian.d.ts +26 -0
  17. package/dist/types/exec/bash-shell-supervisor.d.ts +12 -0
  18. package/dist/types/hashline/parser.d.ts +28 -5
  19. package/dist/types/modes/acp/acp-agent.d.ts +6 -1
  20. package/dist/types/sdk/broker/discovery.d.ts +8 -0
  21. package/dist/types/sdk/broker/ensure.d.ts +1 -0
  22. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +4 -0
  23. package/dist/types/sdk/broker/lifecycle.d.ts +6 -1
  24. package/dist/types/sdk/broker/recovery-backoff.d.ts +62 -0
  25. package/dist/types/sdk/broker/runtime.d.ts +21 -1
  26. package/dist/types/sdk/broker/startup-budget.d.ts +5 -1
  27. package/dist/types/sdk/bus/index.d.ts +1 -0
  28. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  29. package/dist/types/sdk/bus/telegram-daemon.d.ts +1 -0
  30. package/dist/types/sdk/cli/diagnostics-cli.d.ts +18 -0
  31. package/dist/types/sdk/diagnostics/observe-broker.d.ts +185 -0
  32. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  33. package/dist/types/sdk/host/session-runtime.d.ts +7 -0
  34. package/dist/types/sdk/index.d.ts +1 -0
  35. package/dist/types/sdk/prompt-watchdog.d.ts +1 -1
  36. package/dist/types/sdk/router/session-router.d.ts +2 -0
  37. package/dist/types/sdk/session.d.ts +13 -0
  38. package/dist/types/session/agent-session.d.ts +5 -1
  39. package/dist/types/tools/ask-contract.d.ts +75 -254
  40. package/dist/types/tools/bash.d.ts +1 -0
  41. package/package.json +7 -7
  42. package/scripts/build-sdk-package-smoke.ts +5 -0
  43. package/src/cli/public-command-entry.ts +5 -0
  44. package/src/cli/ssh-cli.ts +6 -3
  45. package/src/cli/stats-cli.ts +4 -36
  46. package/src/cli/web-search-cli.ts +9 -3
  47. package/src/cli-commands.ts +14 -0
  48. package/src/cli-main.ts +4 -8
  49. package/src/cli-ordinary.ts +197 -0
  50. package/src/cli.ts +25 -186
  51. package/src/commands/commit.ts +2 -2
  52. package/src/commands/contribution-prep.ts +1 -3
  53. package/src/commands/sdk.ts +60 -2
  54. package/src/commands/update.ts +15 -1
  55. package/src/config/autorouting-tier-map.ts +20 -2
  56. package/src/config/file-lock.ts +91 -2
  57. package/src/config/model-preset-registry.ts +17 -2
  58. package/src/config/model-profile-activation.ts +73 -5
  59. package/src/config/model-profile-contract.ts +4 -1
  60. package/src/config/model-profiles.ts +29 -29
  61. package/src/config/model-registry.ts +45 -17
  62. package/src/config/model-resolver.ts +9 -1
  63. package/src/coordinator-mcp/event-webhook.ts +19 -14
  64. package/src/coordinator-mcp/policy.ts +14 -4
  65. package/src/coordinator-mcp/server.ts +142 -7
  66. package/src/coordinator-mcp/session-reaper.ts +9 -1
  67. package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
  68. package/src/edit/modes/replace.ts +6 -6
  69. package/src/edit/streaming.ts +15 -15
  70. package/src/exa/mcp-client.ts +41 -8
  71. package/src/exec/bash-shell-guardian.ts +184 -34
  72. package/src/exec/bash-shell-supervisor.ts +60 -3
  73. package/src/hashline/execute.ts +51 -3
  74. package/src/hashline/parser.ts +63 -16
  75. package/src/internal-urls/docs-index.generated.ts +29 -28
  76. package/src/memories/index.ts +8 -2
  77. package/src/modes/acp/acp-agent.ts +688 -371
  78. package/src/modes/components/tool-execution.ts +1 -1
  79. package/src/modes/controllers/ssh-command-controller.ts +3 -1
  80. package/src/prompts/tools/ask.md +2 -0
  81. package/src/sdk/broker/broker.ts +46 -0
  82. package/src/sdk/broker/daemon-entry.ts +67 -6
  83. package/src/sdk/broker/discovery.ts +8 -0
  84. package/src/sdk/broker/ensure.ts +156 -20
  85. package/src/sdk/broker/lifecycle-ledger.ts +110 -12
  86. package/src/sdk/broker/lifecycle.ts +108 -34
  87. package/src/sdk/broker/recovery-backoff.ts +135 -0
  88. package/src/sdk/broker/runtime.ts +88 -1
  89. package/src/sdk/broker/startup-budget.ts +6 -1
  90. package/src/sdk/broker/transport.ts +5 -1
  91. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  92. package/src/sdk/bus/index.ts +305 -19
  93. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  94. package/src/sdk/bus/telegram-daemon-control.ts +15 -12
  95. package/src/sdk/bus/telegram-daemon.ts +34 -1
  96. package/src/sdk/cli/diagnostics-cli.ts +247 -0
  97. package/src/sdk/diagnostics/observe-broker.ts +654 -0
  98. package/src/sdk/host/control/dispatch.ts +52 -4
  99. package/src/sdk/host/control/operations.ts +1 -1
  100. package/src/sdk/host/session-runtime.test.ts +40 -2
  101. package/src/sdk/host/session-runtime.ts +112 -8
  102. package/src/sdk/index.ts +1 -0
  103. package/src/sdk/lifecycle-session.ts +1 -0
  104. package/src/sdk/prompt-watchdog.ts +17 -4
  105. package/src/sdk/protocol/operation-registry.ts +1 -1
  106. package/src/sdk/router/session-router.ts +7 -1
  107. package/src/sdk/session.ts +37 -8
  108. package/src/session/agent-session.ts +128 -41
  109. package/src/session/blob-store.ts +78 -33
  110. package/src/session/internal/managed-session-storage.ts +119 -3
  111. package/src/setup/hermes/templates/operator-instructions.v1.md +19 -1
  112. package/src/setup/hermes-setup.ts +4 -1
  113. package/src/slash-commands/builtin-registry.ts +8 -5
  114. package/src/tools/ask-contract.test.ts +76 -1
  115. package/src/tools/ask-contract.ts +57 -6
  116. package/src/tools/ask.ts +16 -7
  117. package/src/tools/bash.ts +77 -29
  118. package/src/tools/descriptors.test.ts +29 -0
  119. package/src/tools/tool-catalog.generated.ts +7 -4
  120. package/src/web/search/index.ts +2 -2
  121. package/dist/types/cli/grep-cli.d.ts +0 -17
  122. package/dist/types/cli/shell-cli.d.ts +0 -8
  123. package/dist/types/commands/grep.d.ts +0 -42
  124. package/dist/types/commands/shell.d.ts +0 -21
  125. package/src/cli/grep-cli.ts +0 -160
  126. package/src/cli/shell-cli.ts +0 -176
  127. package/src/commands/grep.ts +0 -48
  128. package/src/commands/shell.ts +0 -29
@@ -267,133 +267,6 @@ export declare const topologyAskSchema: z.ZodObject<{
267
267
  }, z.core.$strip>>;
268
268
  multi: z.ZodOptional<z.ZodBoolean>;
269
269
  recommended: z.ZodOptional<z.ZodNumber>;
270
- deepInterview: z.ZodOptional<z.ZodType<{
271
- round_id?: string | undefined;
272
- ambiguity: number;
273
- confused_terms?: string[] | undefined;
274
- references?: {
275
- reference_id: string;
276
- label: string;
277
- origin: string;
278
- url?: string | undefined;
279
- excerpt?: string | undefined;
280
- }[] | undefined;
281
- round: number;
282
- component: "review-topology";
283
- dimension: "topology";
284
- intent_contract: {
285
- items: {
286
- id: string;
287
- category: "artifact" | "constraint" | "integration" | "surface";
288
- statement: string;
289
- }[];
290
- confirmation_options: string[];
291
- };
292
- } | {
293
- round_id?: string | undefined;
294
- component: string;
295
- dimension: string;
296
- ambiguity: number;
297
- confused_terms?: string[] | undefined;
298
- references?: {
299
- reference_id: string;
300
- label: string;
301
- origin: string;
302
- url?: string | undefined;
303
- excerpt?: string | undefined;
304
- }[] | undefined;
305
- round: number;
306
- } | {
307
- round_id?: string | undefined;
308
- component: string;
309
- dimension: string;
310
- ambiguity: number;
311
- confused_terms?: string[] | undefined;
312
- references?: {
313
- reference_id: string;
314
- label: string;
315
- origin: string;
316
- url?: string | undefined;
317
- excerpt?: string | undefined;
318
- }[] | undefined;
319
- round: number;
320
- intent_review: {
321
- observed_items: {
322
- id: string;
323
- category: "artifact" | "constraint" | "integration" | "surface";
324
- statement: string;
325
- }[];
326
- supporting_substitutions: {
327
- removed_id: string;
328
- replacement_ids: string[];
329
- rationale: string;
330
- }[];
331
- approval_options: string[];
332
- };
333
- }, unknown, z.core.$ZodTypeInternals<{
334
- round_id?: string | undefined;
335
- ambiguity: number;
336
- confused_terms?: string[] | undefined;
337
- references?: {
338
- reference_id: string;
339
- label: string;
340
- origin: string;
341
- url?: string | undefined;
342
- excerpt?: string | undefined;
343
- }[] | undefined;
344
- round: number;
345
- component: "review-topology";
346
- dimension: "topology";
347
- intent_contract: {
348
- items: {
349
- id: string;
350
- category: "artifact" | "constraint" | "integration" | "surface";
351
- statement: string;
352
- }[];
353
- confirmation_options: string[];
354
- };
355
- } | {
356
- round_id?: string | undefined;
357
- component: string;
358
- dimension: string;
359
- ambiguity: number;
360
- confused_terms?: string[] | undefined;
361
- references?: {
362
- reference_id: string;
363
- label: string;
364
- origin: string;
365
- url?: string | undefined;
366
- excerpt?: string | undefined;
367
- }[] | undefined;
368
- round: number;
369
- } | {
370
- round_id?: string | undefined;
371
- component: string;
372
- dimension: string;
373
- ambiguity: number;
374
- confused_terms?: string[] | undefined;
375
- references?: {
376
- reference_id: string;
377
- label: string;
378
- origin: string;
379
- url?: string | undefined;
380
- excerpt?: string | undefined;
381
- }[] | undefined;
382
- round: number;
383
- intent_review: {
384
- observed_items: {
385
- id: string;
386
- category: "artifact" | "constraint" | "integration" | "surface";
387
- statement: string;
388
- }[];
389
- supporting_substitutions: {
390
- removed_id: string;
391
- replacement_ids: string[];
392
- rationale: string;
393
- }[];
394
- approval_options: string[];
395
- };
396
- }, unknown>>>;
397
270
  workflowGate: z.ZodOptional<z.ZodObject<{
398
271
  stage: z.ZodEnum<{
399
272
  "deep-interview": "deep-interview";
@@ -406,6 +279,34 @@ export declare const topologyAskSchema: z.ZodObject<{
406
279
  question: "question";
407
280
  }>;
408
281
  }, z.core.$strip>>;
282
+ deepInterview: z.ZodObject<{
283
+ round_id: z.ZodOptional<z.ZodString>;
284
+ ambiguity: z.ZodNumber;
285
+ confused_terms: z.ZodOptional<z.ZodArray<z.ZodString>>;
286
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
287
+ reference_id: z.ZodString;
288
+ label: z.ZodString;
289
+ origin: z.ZodString;
290
+ url: z.ZodOptional<z.ZodString>;
291
+ excerpt: z.ZodOptional<z.ZodString>;
292
+ }, z.core.$strict>>>;
293
+ round: z.ZodNumber;
294
+ component: z.ZodLiteral<"review-topology">;
295
+ dimension: z.ZodLiteral<"topology">;
296
+ intent_contract: z.ZodObject<{
297
+ items: z.ZodArray<z.ZodObject<{
298
+ id: z.ZodString;
299
+ category: z.ZodEnum<{
300
+ artifact: "artifact";
301
+ constraint: "constraint";
302
+ integration: "integration";
303
+ surface: "surface";
304
+ }>;
305
+ statement: z.ZodString;
306
+ }, z.core.$strict>>;
307
+ confirmation_options: z.ZodArray<z.ZodString>;
308
+ }, z.core.$strict>;
309
+ }, z.core.$strict>;
409
310
  }, z.core.$strip>>;
410
311
  }, z.core.$strip>;
411
312
  export declare const postTopologyAskSchema: z.ZodObject<{
@@ -417,133 +318,6 @@ export declare const postTopologyAskSchema: z.ZodObject<{
417
318
  }, z.core.$strip>>;
418
319
  multi: z.ZodOptional<z.ZodBoolean>;
419
320
  recommended: z.ZodOptional<z.ZodNumber>;
420
- deepInterview: z.ZodOptional<z.ZodType<{
421
- round_id?: string | undefined;
422
- ambiguity: number;
423
- confused_terms?: string[] | undefined;
424
- references?: {
425
- reference_id: string;
426
- label: string;
427
- origin: string;
428
- url?: string | undefined;
429
- excerpt?: string | undefined;
430
- }[] | undefined;
431
- round: number;
432
- component: "review-topology";
433
- dimension: "topology";
434
- intent_contract: {
435
- items: {
436
- id: string;
437
- category: "artifact" | "constraint" | "integration" | "surface";
438
- statement: string;
439
- }[];
440
- confirmation_options: string[];
441
- };
442
- } | {
443
- round_id?: string | undefined;
444
- component: string;
445
- dimension: string;
446
- ambiguity: number;
447
- confused_terms?: string[] | undefined;
448
- references?: {
449
- reference_id: string;
450
- label: string;
451
- origin: string;
452
- url?: string | undefined;
453
- excerpt?: string | undefined;
454
- }[] | undefined;
455
- round: number;
456
- } | {
457
- round_id?: string | undefined;
458
- component: string;
459
- dimension: string;
460
- ambiguity: number;
461
- confused_terms?: string[] | undefined;
462
- references?: {
463
- reference_id: string;
464
- label: string;
465
- origin: string;
466
- url?: string | undefined;
467
- excerpt?: string | undefined;
468
- }[] | undefined;
469
- round: number;
470
- intent_review: {
471
- observed_items: {
472
- id: string;
473
- category: "artifact" | "constraint" | "integration" | "surface";
474
- statement: string;
475
- }[];
476
- supporting_substitutions: {
477
- removed_id: string;
478
- replacement_ids: string[];
479
- rationale: string;
480
- }[];
481
- approval_options: string[];
482
- };
483
- }, unknown, z.core.$ZodTypeInternals<{
484
- round_id?: string | undefined;
485
- ambiguity: number;
486
- confused_terms?: string[] | undefined;
487
- references?: {
488
- reference_id: string;
489
- label: string;
490
- origin: string;
491
- url?: string | undefined;
492
- excerpt?: string | undefined;
493
- }[] | undefined;
494
- round: number;
495
- component: "review-topology";
496
- dimension: "topology";
497
- intent_contract: {
498
- items: {
499
- id: string;
500
- category: "artifact" | "constraint" | "integration" | "surface";
501
- statement: string;
502
- }[];
503
- confirmation_options: string[];
504
- };
505
- } | {
506
- round_id?: string | undefined;
507
- component: string;
508
- dimension: string;
509
- ambiguity: number;
510
- confused_terms?: string[] | undefined;
511
- references?: {
512
- reference_id: string;
513
- label: string;
514
- origin: string;
515
- url?: string | undefined;
516
- excerpt?: string | undefined;
517
- }[] | undefined;
518
- round: number;
519
- } | {
520
- round_id?: string | undefined;
521
- component: string;
522
- dimension: string;
523
- ambiguity: number;
524
- confused_terms?: string[] | undefined;
525
- references?: {
526
- reference_id: string;
527
- label: string;
528
- origin: string;
529
- url?: string | undefined;
530
- excerpt?: string | undefined;
531
- }[] | undefined;
532
- round: number;
533
- intent_review: {
534
- observed_items: {
535
- id: string;
536
- category: "artifact" | "constraint" | "integration" | "surface";
537
- statement: string;
538
- }[];
539
- supporting_substitutions: {
540
- removed_id: string;
541
- replacement_ids: string[];
542
- rationale: string;
543
- }[];
544
- approval_options: string[];
545
- };
546
- }, unknown>>>;
547
321
  workflowGate: z.ZodOptional<z.ZodObject<{
548
322
  stage: z.ZodEnum<{
549
323
  "deep-interview": "deep-interview";
@@ -556,6 +330,53 @@ export declare const postTopologyAskSchema: z.ZodObject<{
556
330
  question: "question";
557
331
  }>;
558
332
  }, z.core.$strip>>;
333
+ deepInterview: z.ZodUnion<readonly [z.ZodObject<{
334
+ round_id: z.ZodOptional<z.ZodString>;
335
+ component: z.ZodString;
336
+ dimension: z.ZodString;
337
+ ambiguity: z.ZodNumber;
338
+ confused_terms: z.ZodOptional<z.ZodArray<z.ZodString>>;
339
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
340
+ reference_id: z.ZodString;
341
+ label: z.ZodString;
342
+ origin: z.ZodString;
343
+ url: z.ZodOptional<z.ZodString>;
344
+ excerpt: z.ZodOptional<z.ZodString>;
345
+ }, z.core.$strict>>>;
346
+ round: z.ZodNumber;
347
+ }, z.core.$strict>, z.ZodObject<{
348
+ round_id: z.ZodOptional<z.ZodString>;
349
+ component: z.ZodString;
350
+ dimension: z.ZodString;
351
+ ambiguity: z.ZodNumber;
352
+ confused_terms: z.ZodOptional<z.ZodArray<z.ZodString>>;
353
+ references: z.ZodOptional<z.ZodArray<z.ZodObject<{
354
+ reference_id: z.ZodString;
355
+ label: z.ZodString;
356
+ origin: z.ZodString;
357
+ url: z.ZodOptional<z.ZodString>;
358
+ excerpt: z.ZodOptional<z.ZodString>;
359
+ }, z.core.$strict>>>;
360
+ round: z.ZodNumber;
361
+ intent_review: z.ZodObject<{
362
+ observed_items: z.ZodArray<z.ZodObject<{
363
+ id: z.ZodString;
364
+ category: z.ZodEnum<{
365
+ artifact: "artifact";
366
+ constraint: "constraint";
367
+ integration: "integration";
368
+ surface: "surface";
369
+ }>;
370
+ statement: z.ZodString;
371
+ }, z.core.$strict>>;
372
+ supporting_substitutions: z.ZodArray<z.ZodObject<{
373
+ removed_id: z.ZodString;
374
+ replacement_ids: z.ZodArray<z.ZodString>;
375
+ rationale: z.ZodString;
376
+ }, z.core.$strict>>;
377
+ approval_options: z.ZodArray<z.ZodString>;
378
+ }, z.core.$strict>;
379
+ }, z.core.$strict>]>;
559
380
  }, z.core.$strip>>;
560
381
  }, z.core.$strip>;
561
382
  export declare const ordinaryAskSchema: z.ZodObject<{
@@ -10,6 +10,7 @@ import type { ToolSession } from ".";
10
10
  import { type OutputMeta } from "./output-meta";
11
11
  export { STEER_FOLD_GRACE_MS, steerFoldReasonLine } from "./steer-fold";
12
12
  export declare const BASH_DEFAULT_PREVIEW_LINES = 10;
13
+ export declare const MANAGED_OWNER_BASH_ENV: readonly ["GJC_TMUX_OWNER_STATE_DIR", "GJC_TMUX_OWNER_GENERATION", "GJC_MANAGED_OWNER_RUN_ID", "GJC_MANAGED_OWNER_INCARNATION", "GJC_MANAGED_OWNER_CHILD_TOKEN", "GJC_MANAGED_OWNER_COMMAND_JSON", "GJC_MANAGED_OWNER_REDACT_COMMAND", "GJC_MANAGED_OWNER_PREDECESSOR_TOKEN", "GJC_MANAGED_OWNER_PREDECESSOR_GENERATION", "GJC_MANAGED_OWNER_PREDECESSOR_RUN_ID", "GJC_MANAGED_OWNER_PREDECESSOR_INCARNATION", "GJC_MANAGED_OWNER_TRANSCRIPT_PATH", "GJC_TMUX_OWNER_SERVER_KEY", "GJC_TMUX_LAUNCHED"];
13
14
  export type BashOriginalArtifactSaveResult = BashArtifactSaveResult;
14
15
  /**
15
16
  * Lift a leading `cd <dir> &&` into the tool cwd only when `<dir>` is exactly
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.18.1",
4
+ "version": "0.18.6",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -57,12 +57,12 @@
57
57
  "@agentclientprotocol/sdk": "1.3.0",
58
58
  "@babel/parser": "^7.29.3",
59
59
  "@mozilla/readability": "^0.6.0",
60
- "@gajae-code/stats": "0.18.1",
61
- "@gajae-code/agent-core": "0.18.1",
62
- "@gajae-code/ai": "0.18.1",
63
- "@gajae-code/natives": "0.18.1",
64
- "@gajae-code/tui": "0.18.1",
65
- "@gajae-code/utils": "0.18.1",
60
+ "@gajae-code/stats": "0.18.6",
61
+ "@gajae-code/agent-core": "0.18.6",
62
+ "@gajae-code/ai": "0.18.6",
63
+ "@gajae-code/natives": "0.18.6",
64
+ "@gajae-code/tui": "0.18.6",
65
+ "@gajae-code/utils": "0.18.6",
66
66
  "@puppeteer/browsers": "^2.13.0",
67
67
  "@types/turndown": "5.0.6",
68
68
  "@xterm/headless": "^6.0.0",
@@ -12,6 +12,7 @@ const tuiPackageDir = path.resolve(packageDir, "../tui");
12
12
  const nativesPackageDir = path.resolve(packageDir, "../natives");
13
13
  const linuxX64PackageDir = path.resolve(packageDir, "../natives-linux-x64");
14
14
  const utilsPackageDir = path.resolve(packageDir, "../utils");
15
+ const statsPackageDir = path.resolve(packageDir, "../stats");
15
16
  const manifestsDir = path.join(packageDir, "test/manifests");
16
17
  // v2 intentionally removes eager concrete-tool exports to preserve the SDK cold boundary.
17
18
  const baselineVersion = 2;
@@ -51,6 +52,7 @@ async function runSmoke(): Promise<Surface> {
51
52
  const nativesTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], nativesPackageDir);
52
53
  const linuxX64Tarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], stagedLinuxX64Dir);
53
54
  const utilsTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], utilsPackageDir);
55
+ const statsTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], statsPackageDir);
54
56
  const codingAgentTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], packageDir);
55
57
  const agentTarballPath = path.isAbsolute(agentTarball) ? agentTarball : path.join(agentPackageDir, agentTarball);
56
58
  const aiTarballPath = path.isAbsolute(aiTarball) ? aiTarball : path.join(aiPackageDir, aiTarball);
@@ -62,6 +64,7 @@ async function runSmoke(): Promise<Surface> {
62
64
  ? linuxX64Tarball
63
65
  : path.join(stagedLinuxX64Dir, linuxX64Tarball);
64
66
  const utilsTarballPath = path.isAbsolute(utilsTarball) ? utilsTarball : path.join(utilsPackageDir, utilsTarball);
67
+ const statsTarballPath = path.isAbsolute(statsTarball) ? statsTarball : path.join(statsPackageDir, statsTarball);
65
68
  const codingAgentTarballPath = path.isAbsolute(codingAgentTarball)
66
69
  ? codingAgentTarball
67
70
  : path.join(packageDir, codingAgentTarball);
@@ -79,6 +82,7 @@ async function runSmoke(): Promise<Surface> {
79
82
  "@gajae-code/natives": `file:${nativesTarballPath}`,
80
83
  "@gajae-code/natives-linux-x64": `file:${linuxX64TarballPath}`,
81
84
  "@gajae-code/utils": `file:${utilsTarballPath}`,
85
+ "@gajae-code/stats": `file:${statsTarballPath}`,
82
86
  },
83
87
  overrides: {
84
88
  "@gajae-code/agent-core": `file:${agentTarballPath}`,
@@ -87,6 +91,7 @@ async function runSmoke(): Promise<Surface> {
87
91
  "@gajae-code/natives": `file:${nativesTarballPath}`,
88
92
  "@gajae-code/natives-linux-x64": `file:${linuxX64TarballPath}`,
89
93
  "@gajae-code/utils": `file:${utilsTarballPath}`,
94
+ "@gajae-code/stats": `file:${statsTarballPath}`,
90
95
  },
91
96
  },
92
97
  null,
@@ -288,6 +288,11 @@ export function isSdkInternalArgv(argv: readonly string[]): boolean {
288
288
  return (
289
289
  (argv[0] === "session-host-internal" && argv.length === 1) ||
290
290
  (argv[0] === "broker-internal" &&
291
+ argv.length === 3 &&
292
+ argv[1] === "--agent-dir" &&
293
+ typeof argv[2] === "string" &&
294
+ isSafeSdkInternalAgentDir(argv[2])) ||
295
+ (argv[0] === "broker-trampoline-internal" &&
291
296
  argv.length === 3 &&
292
297
  argv[1] === "--agent-dir" &&
293
298
  typeof argv[2] === "string" &&
@@ -74,9 +74,12 @@ async function handleAdd(cmd: SSHCommandArgs): Promise<void> {
74
74
  return;
75
75
  }
76
76
 
77
- // Validate port if provided
77
+ // Validate port if provided. `Number.parseInt` accepts trailing garbage
78
+ // (parseInt("22oops") === 22, parseInt("2222.5") === 2222), so require
79
+ // the whole token to be digits before parsing.
80
+ let port: number | undefined;
78
81
  if (cmd.flags.port !== undefined) {
79
- const port = Number.parseInt(cmd.flags.port, 10);
82
+ port = /^\d+$/.test(cmd.flags.port) ? Number.parseInt(cmd.flags.port, 10) : Number.NaN;
80
83
  if (Number.isNaN(port) || port < 1 || port > 65535) {
81
84
  process.stdout.write(chalk.red("Error: Port must be an integer between 1 and 65535\n"));
82
85
  process.exitCode = 1;
@@ -86,7 +89,7 @@ async function handleAdd(cmd: SSHCommandArgs): Promise<void> {
86
89
 
87
90
  const hostConfig: SSHHostConfig = { host };
88
91
  if (cmd.flags.user) hostConfig.username = cmd.flags.user;
89
- if (cmd.flags.port) hostConfig.port = Number.parseInt(cmd.flags.port, 10);
92
+ if (port !== undefined) hostConfig.port = port;
90
93
  if (cmd.flags.key) hostConfig.keyPath = cmd.flags.key;
91
94
  if (cmd.flags.desc) hostConfig.description = cmd.flags.desc;
92
95
  if (cmd.flags.compat) hostConfig.compat = true;
@@ -70,41 +70,6 @@ export interface StatsCommandArgs {
70
70
  summary: boolean;
71
71
  }
72
72
 
73
- // =============================================================================
74
- // Argument Parser
75
- // =============================================================================
76
-
77
- /**
78
- * Parse stats subcommand arguments.
79
- * Returns undefined if not a stats command.
80
- */
81
- export function parseStatsArgs(args: string[]): StatsCommandArgs | undefined {
82
- if (args.length === 0 || args[0] !== "stats") {
83
- return undefined;
84
- }
85
-
86
- const result: StatsCommandArgs = {
87
- port: 3847,
88
- json: false,
89
- summary: false,
90
- };
91
-
92
- for (let i = 1; i < args.length; i++) {
93
- const arg = args[i];
94
- if (arg === "--json" || arg === "-j") {
95
- result.json = true;
96
- } else if (arg === "--summary" || arg === "-s") {
97
- result.summary = true;
98
- } else if ((arg === "--port" || arg === "-p") && i + 1 < args.length) {
99
- result.port = parseInt(args[++i], 10);
100
- } else if (arg.startsWith("--port=")) {
101
- result.port = parseInt(arg.split("=")[1], 10);
102
- }
103
- }
104
-
105
- return result;
106
- }
107
-
108
73
  function formatCost(n: number): string {
109
74
  if (n < 0.01) return `$${n.toFixed(4)}`;
110
75
  if (n < 1) return `$${n.toFixed(3)}`;
@@ -131,7 +96,10 @@ export async function runStatsCommand(cmd: StatsCommandArgs): Promise<void> {
131
96
  const { processed, files } = await syncAllSessions({ onProgress: progress.onProgress });
132
97
  progress.finish();
133
98
  const total = await getTotalMessageCount();
134
- console.log(`Synced ${processed} new entries from ${files} files (${total} total)\n`);
99
+ const synced = `Synced ${processed} new entries from ${files} files (${total} total)\n`;
100
+ // `--json` stdout must be exactly the JSON document so it can be piped into a parser.
101
+ if (cmd.json) process.stderr.write(`${synced}\n`);
102
+ else console.log(synced);
135
103
 
136
104
  if (cmd.json) {
137
105
  const stats = await getDashboardStats();
@@ -95,7 +95,10 @@ export function parseSearchArgs(args: string[]): SearchCommandArgs | undefined {
95
95
  result.recency = value() as SearchCommandArgs["recency"];
96
96
  consumeSeparateValue();
97
97
  } else if (arg === "--limit" || arg === "-l") {
98
- result.limit = Number.parseInt(value(), 10);
98
+ const raw = value();
99
+ // `Number.parseInt` accepts trailing garbage ("5x" -> 5); leave
100
+ // anything that is not plain digits as NaN so it is rejected below.
101
+ result.limit = /^\d+$/.test(raw) ? Number.parseInt(raw, 10) : Number.NaN;
99
102
  consumeSeparateValue();
100
103
  } else if (arg === "--xai-mode") {
101
104
  result.xaiSearchMode = value() as SearchCommandArgs["xaiSearchMode"];
@@ -164,8 +167,11 @@ export async function runSearchCommand(cmd: SearchCommandArgs): Promise<void> {
164
167
  process.exit(1);
165
168
  }
166
169
 
167
- if (cmd.limit !== undefined && Number.isNaN(cmd.limit)) {
168
- process.stderr.write(`${chalk.red("Error: --limit must be a number")}\n`);
170
+ // `Flags.integer` accepts `0` and negative values; providers forward them
171
+ // as `num_results` and several slice sources with them (`slice(0, -3)`
172
+ // silently drops the last three results).
173
+ if (cmd.limit !== undefined && (!Number.isSafeInteger(cmd.limit) || cmd.limit < 1)) {
174
+ process.stderr.write(`${chalk.red("Error: --limit must be a positive integer")}\n`);
169
175
  process.exit(1);
170
176
  }
171
177
 
@@ -0,0 +1,14 @@
1
+ import type { CommandEntry } from "@gajae-code/utils/cli";
2
+
3
+ /**
4
+ * Public-family hooks kept available for private-worker tests without loading the
5
+ * full registry.
6
+ *
7
+ * This is the single shared array: the inert entry (`cli.ts`) and the ordinary
8
+ * dispatcher (`cli-ordinary.ts`) both re-export THIS object, so a test that
9
+ * mutates or injects an entry keeps affecting the dispatcher.
10
+ */
11
+ export const commands: CommandEntry[] = [
12
+ { name: "sdk", load: () => import("./commands/sdk").then(module => module.default) },
13
+ { name: "daemon", load: () => import("./commands/daemon").then(module => module.default) },
14
+ ];
package/src/cli-main.ts CHANGED
@@ -95,14 +95,10 @@ async function showHelp(config: CliConfig): Promise<void> {
95
95
  }
96
96
 
97
97
  async function installRuntimeGlobals(): Promise<void> {
98
- const { installH2Fetch } = await import("@gajae-code/ai/utils/h2-fetch");
99
- // Activate HTTP/2 for all `fetch()` calls (provider streams, OAuth, model
100
- // discovery, web tools). Bun's HTTP/2 client is gated on a startup flag we
101
- // can't toggle from JS, so we patch globalThis.fetch to pass
102
- // `protocol: "http2"` per request, with transparent HTTP/1.1 fallback on
103
- // `HTTP2Unsupported`. See @gajae-code/ai/utils/h2-fetch for details.
104
- installH2Fetch();
105
-
98
+ // fetch() deliberately stays on HTTP/1.1. Bun's HTTP/2 client (per-request
99
+ // `protocol: "http2"`) wedges a pooled connection while uploading large
100
+ // request bodies (~300KB): every later request on it waits forever for
101
+ // response headers. Do not re-enable HTTP/2 without re-running that probe.
106
102
  const { warnIfMacOSNoFileLimitTooLow } = await import("./cli/nofile-limit");
107
103
  warnIfMacOSNoFileLimitTooLow();
108
104