@moxxy/sdk 0.19.0 → 0.20.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 (53) hide show
  1. package/dist/errors.d.ts +1 -1
  2. package/dist/errors.d.ts.map +1 -1
  3. package/dist/errors.js.map +1 -1
  4. package/dist/event-store.d.ts +113 -0
  5. package/dist/event-store.d.ts.map +1 -0
  6. package/dist/event-store.js +2 -0
  7. package/dist/event-store.js.map +1 -0
  8. package/dist/events.d.ts +1 -1
  9. package/dist/events.d.ts.map +1 -1
  10. package/dist/hooks.d.ts +6 -0
  11. package/dist/hooks.d.ts.map +1 -1
  12. package/dist/index.d.ts +4 -2
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/mode/collect-stream.d.ts.map +1 -1
  16. package/dist/mode/collect-stream.js +1 -0
  17. package/dist/mode/collect-stream.js.map +1 -1
  18. package/dist/mode/stuck-loop.d.ts +20 -6
  19. package/dist/mode/stuck-loop.d.ts.map +1 -1
  20. package/dist/mode/stuck-loop.js +14 -3
  21. package/dist/mode/stuck-loop.js.map +1 -1
  22. package/dist/mode-helpers.d.ts +1 -1
  23. package/dist/mode-helpers.d.ts.map +1 -1
  24. package/dist/mode-helpers.js.map +1 -1
  25. package/dist/mode.d.ts +9 -0
  26. package/dist/mode.d.ts.map +1 -1
  27. package/dist/mode.js.map +1 -1
  28. package/dist/plugin.d.ts +10 -1
  29. package/dist/plugin.d.ts.map +1 -1
  30. package/dist/services.d.ts +47 -0
  31. package/dist/services.d.ts.map +1 -0
  32. package/dist/services.js +2 -0
  33. package/dist/services.js.map +1 -0
  34. package/dist/session-like.d.ts +36 -2
  35. package/dist/session-like.d.ts.map +1 -1
  36. package/dist/tool-dispatch.d.ts.map +1 -1
  37. package/dist/tool-dispatch.js +1 -0
  38. package/dist/tool-dispatch.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/errors.ts +1 -0
  41. package/src/event-store.ts +118 -0
  42. package/src/events.ts +1 -0
  43. package/src/hooks.ts +6 -0
  44. package/src/index.ts +14 -0
  45. package/src/mode/collect-stream.ts +1 -0
  46. package/src/mode/stuck-loop.ts +28 -11
  47. package/src/mode-helpers.ts +1 -0
  48. package/src/mode.ts +9 -0
  49. package/src/plugin.ts +10 -1
  50. package/src/services.ts +47 -0
  51. package/src/session-like.ts +38 -2
  52. package/src/stuck-loop.test.ts +16 -3
  53. package/src/tool-dispatch.ts +1 -0
@@ -291,6 +291,30 @@ export interface LoadedPluginView {
291
291
  readonly kinds: ReadonlyArray<string>;
292
292
  }
293
293
 
294
+ /** One swappable contribution within a {@link CategoryView}. */
295
+ export interface CategoryItemView {
296
+ /** Contribution name (e.g. provider `anthropic`, compactor `summarize`). */
297
+ readonly name: string;
298
+ /** Whether this item is the active default for its category. */
299
+ readonly isDefault: boolean;
300
+ }
301
+
302
+ /**
303
+ * One registry category in {@link PluginsAdminView.categories} — the active
304
+ * default plus the available items to swap between. Powers the per-category
305
+ * tabs in the `/plugins` picker and the `list_defaults` tool.
306
+ */
307
+ export interface CategoryView {
308
+ /** Registry kind, e.g. `provider` | `compactor` | `mode`. */
309
+ readonly category: string;
310
+ /** Active default contribution name, or null when the category is empty. */
311
+ readonly active: string | null;
312
+ /** The protected floor's name (never disableable), or null when none. */
313
+ readonly floor: string | null;
314
+ /** Swappable contributions registered for this category. */
315
+ readonly items: ReadonlyArray<CategoryItemView>;
316
+ }
317
+
294
318
  /**
295
319
  * The slice of plugin management a channel needs to drive the `/plugins`
296
320
  * picker: which plugins are disabled, what's installable, and a persist+
@@ -301,12 +325,24 @@ export interface LoadedPluginView {
301
325
  export interface PluginsAdminView {
302
326
  /** Currently-loaded plugins with their contribution kinds (for kind tabs). */
303
327
  loaded(): ReadonlyArray<LoadedPluginView>;
304
- /** Package names currently disabled (config `plugins[name].enabled=false`). */
328
+ /** Package names currently disabled (config `plugins.packages[name].enabled=false`). */
305
329
  disabled(): ReadonlyArray<string>;
330
+ /** Kernel package names that cannot be disabled (swap their default instead). */
331
+ protectedPackages(): ReadonlyArray<string>;
306
332
  /** Curated installable-plugin catalog for the picker's "Installable" tab. */
307
333
  catalog(): ReadonlyArray<InstallablePluginView>;
308
- /** Persist `plugins[name].enabled` AND apply it to the live session. */
334
+ /** Persist `plugins.packages[name].enabled` AND apply it to the live session. */
309
335
  setEnabled(packageName: string, enabled: boolean): Promise<void>;
336
+ /**
337
+ * Per-category active default + swappable items (the swap axis). Powers the
338
+ * `/plugins` category tabs and the `list_defaults` tool.
339
+ */
340
+ categories(): ReadonlyArray<CategoryView>;
341
+ /**
342
+ * Persist `plugins.<category>.default` AND apply it to the live session
343
+ * (`setActive`). Rejects an unknown category or an unregistered name.
344
+ */
345
+ setCategoryDefault(category: string, name: string): Promise<void>;
310
346
  }
311
347
 
312
348
  /**
@@ -3,7 +3,7 @@ import { createStuckLoopDetector, stableHash } from './mode-helpers.js';
3
3
 
4
4
  describe('createStuckLoopDetector', () => {
5
5
  it('trips on exact-input repeats at repeatThreshold', () => {
6
- const d = createStuckLoopDetector(); // repeatThreshold 3
6
+ const d = createStuckLoopDetector({ repeatThreshold: 3 });
7
7
  const input = { x: 1 };
8
8
  expect(d.record('Read', input).stuck).toBe(false);
9
9
  expect(d.record('Read', input).stuck).toBe(false);
@@ -11,8 +11,21 @@ describe('createStuckLoopDetector', () => {
11
11
  expect(sig).toMatchObject({ stuck: true, count: 3, kind: 'exact' });
12
12
  });
13
13
 
14
+ it('uses a generous default exact threshold (does not trip on a few repeats)', () => {
15
+ const d = createStuckLoopDetector(); // default repeatThreshold = 8
16
+ const input = { x: 1 };
17
+ for (let i = 0; i < 7; i++) expect(d.record('Read', input).stuck).toBe(false);
18
+ expect(d.record('Read', input).stuck).toBe(true); // 8th identical call trips
19
+ });
20
+
21
+ it('never trips when disabled (relies on maxIterations alone)', () => {
22
+ const d = createStuckLoopDetector({ enabled: false, repeatThreshold: 2 });
23
+ const input = { x: 1 };
24
+ for (let i = 0; i < 20; i++) expect(d.record('Read', input).stuck).toBe(false);
25
+ });
26
+
14
27
  it('trips on same-target near-dups even when volatile args vary', () => {
15
- const d = createStuckLoopDetector(); // nearThreshold 5
28
+ const d = createStuckLoopDetector({ repeatThreshold: 3 }); // nearThreshold 5
16
29
  const url = 'https://example.com/big';
17
30
  // Same url, different maxBytes each time — exact check never fires.
18
31
  for (let i = 0; i < 4; i++) {
@@ -44,7 +57,7 @@ describe('createStuckLoopDetector', () => {
44
57
  // dispatch path; a throw there crashes the whole turn. These assert it stays
45
58
  // total on hostile/partial input — the worst case the provider can hand us.
46
59
  it('does not throw recording a tool input with a circular reference', () => {
47
- const d = createStuckLoopDetector();
60
+ const d = createStuckLoopDetector({ repeatThreshold: 3 });
48
61
  const input: Record<string, unknown> = { a: 1 };
49
62
  input.self = input;
50
63
  expect(() => d.record('weird', input)).not.toThrow();
@@ -37,6 +37,7 @@ export async function* dispatchToolCall(
37
37
  cwd: ctx.cwd,
38
38
  log: ctx.log,
39
39
  env: ctx.env,
40
+ services: ctx.services,
40
41
  turnId: ctx.turnId,
41
42
  iteration,
42
43
  call: { callId: asToolCallId(t.id), name: t.name, input: t.input },