dsh-codex-subscription 2.1.0-beta.2 → 2.1.0-beta.3

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.
package/lib/index.js CHANGED
@@ -60,7 +60,8 @@ const IMAGE_FEATURE_DEFAULTS = Object.freeze({
60
60
  imageViewer: true,
61
61
  imageAnnotations: true,
62
62
  imageSketch: false,
63
- imageSketchAgent: false
63
+ imageSketchAgent: false,
64
+ imageSketchAgentPreview: false
64
65
  });
65
66
  function readImageFeatures(value = {}) {
66
67
  return Object.fromEntries(Object.entries(IMAGE_FEATURE_DEFAULTS).map(([key, fallback]) => [key, typeof value?.[key] === "boolean" ? value[key] : fallback]));
@@ -350,6 +351,7 @@ const RPC_ENDPOINTS = Object.freeze([
350
351
  "image/original/chunk",
351
352
  "sketch/connect",
352
353
  "sketch/poll",
354
+ "sketch/claim",
353
355
  "sketch/result",
354
356
  "sketch/disconnect"
355
357
  ]);
@@ -435,7 +437,8 @@ function createSketchAgentBridge({ enabled, now = Date.now, timeoutMs = 2e4 }) {
435
437
  const entry = {
436
438
  token: randomUUID(),
437
439
  seen: now(),
438
- tasks: /* @__PURE__ */ new Map()
440
+ tasks: /* @__PURE__ */ new Map(),
441
+ cancelled: []
439
442
  };
440
443
  sessions.set(payload.sessionId, entry);
441
444
  return {
@@ -446,15 +449,25 @@ function createSketchAgentBridge({ enabled, now = Date.now, timeoutMs = 2e4 }) {
446
449
  const entry = find(payload);
447
450
  if (endpoint === "sketch/poll") return {
448
451
  ok: true,
449
- value: [...entry.tasks].filter(([, t]) => !t.delivered).map(([id, t]) => {
452
+ value: [...entry.cancelled.splice(0).map((id) => ({
453
+ id,
454
+ cancelled: true
455
+ })), ...[...entry.tasks].filter(([, t]) => !t.delivered).map(([id, t]) => {
450
456
  t.delivered = true;
451
457
  return {
452
458
  id,
453
459
  request: t.request,
454
460
  expiresAt: t.expiresAt
455
461
  };
456
- })
462
+ })]
457
463
  };
464
+ if (endpoint === "sketch/claim") {
465
+ const task = entry.tasks.get(payload.id);
466
+ return {
467
+ ok: true,
468
+ value: Boolean(task && task.delivered && task.expiresAt > now())
469
+ };
470
+ }
458
471
  if (endpoint === "sketch/disconnect") {
459
472
  fail(entry, "Sketch board closed");
460
473
  sessions.delete(payload.sessionId);
@@ -500,8 +513,15 @@ function createSketchAgentBridge({ enabled, now = Date.now, timeoutMs = 2e4 }) {
500
513
  entry.tasks.delete(id);
501
514
  callback(value);
502
515
  };
503
- const abort = () => finish(reject, Error("Sketch operation interrupted; inspect before retrying"));
504
- const timer = setTimeout(() => finish(reject, Error("Sketch response timed out; inspect before retrying")), timeoutMs);
516
+ const cancel = (message) => {
517
+ if (entry.tasks.get(id)?.delivered) {
518
+ entry.cancelled.push(id);
519
+ if (entry.cancelled.length > 32) entry.cancelled.shift();
520
+ }
521
+ finish(reject, Error(message));
522
+ };
523
+ const abort = () => cancel("Sketch operation interrupted; inspect recentRequests before retrying");
524
+ const timer = setTimeout(() => cancel("Sketch response timed out; inspect recentRequests before retrying"), timeoutMs);
505
525
  entry.tasks.set(id, {
506
526
  request,
507
527
  expiresAt: now() + timeoutMs,
@@ -520,11 +540,108 @@ function createSketchAgentBridge({ enabled, now = Date.now, timeoutMs = 2e4 }) {
520
540
  };
521
541
  }
522
542
  //#endregion
543
+ //#region src/sketch-command-schema.js
544
+ const number = { type: "number" };
545
+ const string = { type: "string" };
546
+ const object = (properties) => ({
547
+ type: "object",
548
+ additionalProperties: false,
549
+ properties
550
+ });
551
+ const style = {
552
+ color: string,
553
+ width: number,
554
+ opacity: number,
555
+ fill: { type: "boolean" },
556
+ text: string,
557
+ points: {
558
+ type: "array",
559
+ items: object({
560
+ x: {
561
+ ...number,
562
+ required: true
563
+ },
564
+ y: {
565
+ ...number,
566
+ required: true
567
+ }
568
+ })
569
+ }
570
+ };
571
+ const sketchCommandArray = {
572
+ type: "array",
573
+ items: object({
574
+ op: {
575
+ type: "string",
576
+ required: true,
577
+ enum: [
578
+ "stroke",
579
+ "object",
580
+ "layer",
581
+ "resize"
582
+ ]
583
+ },
584
+ id: {
585
+ oneOf: [{ type: "string" }, { type: "integer" }],
586
+ description: "Object string ID; layer commands use integer IDs."
587
+ },
588
+ layer: { type: "integer" },
589
+ shape: {
590
+ type: "string",
591
+ enum: [
592
+ "pen",
593
+ "line",
594
+ "arrow",
595
+ "text",
596
+ "rectangle",
597
+ "circle",
598
+ "polygon",
599
+ "bezier",
600
+ "eraser"
601
+ ]
602
+ },
603
+ ...style,
604
+ action: {
605
+ type: "string",
606
+ enum: [
607
+ "update",
608
+ "duplicate",
609
+ "delete",
610
+ "add",
611
+ "select",
612
+ "rename",
613
+ "visible",
614
+ "up",
615
+ "down",
616
+ "clear"
617
+ ]
618
+ },
619
+ value: string,
620
+ ratio: {
621
+ type: "string",
622
+ enum: [
623
+ "1:1",
624
+ "4:3",
625
+ "3:4",
626
+ "16:9",
627
+ "9:16"
628
+ ]
629
+ },
630
+ patch: object(style),
631
+ transform: object({
632
+ dx: number,
633
+ dy: number,
634
+ scaleX: number,
635
+ scaleY: number
636
+ })
637
+ })
638
+ };
639
+ //#endregion
523
640
  //#region src/sketch-agent-tool.js
524
641
  function createSketchAgentTool(bridge, attachments) {
525
642
  return defineTool({
526
643
  name: "codex_sketch",
527
- description: "Edit the sketch board in this session using native editable strokes and layers. Only use when asked to draw or edit a sketch. Start with inspect for the documentId, revision and command reference. Apply atomic batches, preview between stages, and save the finished draft. Never generates AI images, sends messages or attaches images automatically. Inspect automatically opens the board in the currently viewed session. Do not ask the user to open it first. If the session is not visible in DSH, ask them to switch to it. On timeout inspect before retrying; reuse the exact requestId only for the same request.",
644
+ description: "Edit the sketch board in this session using native editable strokes and layers. Use for @sketch requests and explicit follow-up edits to that drawing. The toolbar pen button is for manual drawing; do not require the user to open it. Start with inspect for the runId, documentId, revision and command reference. Apply atomic batches, preview between stages, and call finish to save the finished draft and release the editing lock. save is only a checkpoint. finish returns an image only when the user enables experimental preview feedback. Closing the board does not stop drawing. If the user stops drawing, do not retry. Never generates AI images, sends messages or attaches images automatically. Inspect automatically opens the board in the currently viewed session. Do not ask the user to open it first. If the session is not visible in DSH, ask them to switch to it. On timeout inspect before retrying; reuse the exact requestId only for the same request.",
528
645
  parameters: {
529
646
  action: {
530
647
  type: "string",
@@ -533,28 +650,45 @@ function createSketchAgentTool(bridge, attachments) {
533
650
  "inspect",
534
651
  "apply",
535
652
  "preview",
536
- "save"
653
+ "save",
654
+ "finish"
537
655
  ]
538
656
  },
657
+ runId: {
658
+ type: "string",
659
+ description: "From inspect; required for all other actions. Never reuse a stopped run."
660
+ },
539
661
  documentId: {
540
662
  type: "string",
541
663
  description: "From inspect; required except for inspect."
542
664
  },
543
665
  revision: {
544
666
  type: "integer",
545
- description: "From latest response; required for apply/save."
667
+ description: "From latest response; required for apply/save/finish."
546
668
  },
547
669
  requestId: {
548
670
  type: "string",
549
- description: "Unique id for apply/save; exact retries are deduplicated."
671
+ description: "Unique id for apply/save/finish; exact retries are deduplicated. After timeout inspect recentRequests before repeating a write."
550
672
  },
551
673
  commands: {
552
- type: "string",
553
- description: "JSON array of native commands described by inspect. Required for apply."
674
+ oneOf: [sketchCommandArray, { type: "string" }],
675
+ description: "Prefer a native command array. Legacy JSON string also accepted. Required for apply. Use named objects and update existing IDs; use Bezier for curves, not hundreds of pen points."
554
676
  },
555
677
  name: {
556
678
  type: "string",
557
- description: "Draft name for save."
679
+ description: "Draft name for save/finish."
680
+ },
681
+ offset: {
682
+ type: "integer",
683
+ description: "inspect only: object list offset, default 0. Follow nextOffset for further pages."
684
+ },
685
+ objectId: {
686
+ type: "string",
687
+ description: "inspect only: return full editable geometry for this object, in layer (defaults to active layer)."
688
+ },
689
+ layer: {
690
+ type: "integer",
691
+ description: "inspect only: layer containing objectId."
558
692
  }
559
693
  },
560
694
  timeoutMs: 25e3,
@@ -564,9 +698,10 @@ function createSketchAgentTool(bridge, attachments) {
564
698
  if (typeof sessionId !== "string") throw Error("A session-owned sketch call is required");
565
699
  const request = { ...args };
566
700
  if (args.action === "apply") try {
567
- request.commands = JSON.parse(args.commands);
701
+ request.commands = typeof args.commands === "string" ? JSON.parse(args.commands) : args.commands;
702
+ if (!Array.isArray(request.commands)) throw Error();
568
703
  } catch {
569
- throw Error("commands must be a JSON array");
704
+ throw Error("commands must be a native array or JSON array string");
570
705
  }
571
706
  const value = await bridge.request(sessionId, request, exec.signal);
572
707
  if (value.png) {
@@ -1835,7 +1970,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
1835
1970
  Object.freeze(["0.82.1", "0.85.1"]);
1836
1971
  //#endregion
1837
1972
  //#region src/version.js
1838
- const PACKAGE_VERSION = "2.1.0-beta.2";
1973
+ const PACKAGE_VERSION = "2.1.0-beta.3";
1839
1974
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
1840
1975
  //#endregion
1841
1976
  //#region src/model-catalog.js
@@ -2498,7 +2633,7 @@ function createCodexImageTool(options) {
2498
2633
  const attachments = options.attachments;
2499
2634
  return defineTool({
2500
2635
  name: CODEX_IMAGE_TOOL_NAME,
2501
- description: "Generate or edit images only when the user asks for image output, not when merely discussing images. Uses the signed-in Codex subscription. For a new image, omit referenceImages. For edits, copy complete references only for the images the user selected; obtain missing references using read_image. Never substitute paths, unrelated images, or text-only generation for an edit. For numbered annotations, include the clean source and location-reference image, preserve the requested changes and coordinates in the prompt, and remove guidance markers from the result. If the intended references cannot be identified, ask rather than guessing.",
2636
+ description: "Generate or edit images only when the user asks for image output, not when merely discussing images. Uses the signed-in Codex subscription. For a new image, omit referenceImages. For edits, copy attachmentId only from the selected session image block; the host supplies its metadata. Never call read_image for an attachmentId or attachment filename. Use read_image only for an actual local file whose reference is not already in the conversation. Never substitute paths, unrelated images, or text-only generation for an edit. For numbered annotations, include the clean source and location-reference image, preserve the requested changes and coordinates in the prompt, and remove guidance markers from the result. If the intended references cannot be identified, ask rather than guessing.",
2502
2637
  parameters: {
2503
2638
  model: {
2504
2639
  type: "string",
@@ -2537,7 +2672,7 @@ function createCodexImageTool(options) {
2537
2672
  },
2538
2673
  referenceImages: {
2539
2674
  type: "array",
2540
- description: "Optional explicit references to 1-5 prior images to edit. Copy each complete reference from the session image block or read_image result. Omit only for a new image; an invalid reference must be fixed and retried rather than omitted.",
2675
+ description: "Optional references to 1-5 selected images. For session images provide only attachmentId; the host resolves trusted metadata. Omit only for a new image; never drop an invalid reference to bypass editing.",
2541
2676
  items: {
2542
2677
  type: "object",
2543
2678
  additionalProperties: false,
@@ -2549,19 +2684,19 @@ function createCodexImageTool(options) {
2549
2684
  },
2550
2685
  mediaType: {
2551
2686
  type: "string",
2552
- required: true
2687
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2553
2688
  },
2554
2689
  bytes: {
2555
2690
  type: "integer",
2556
- required: true
2691
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2557
2692
  },
2558
2693
  width: {
2559
2694
  type: "integer",
2560
- required: true
2695
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2561
2696
  },
2562
2697
  height: {
2563
2698
  type: "integer",
2564
- required: true
2699
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2565
2700
  },
2566
2701
  name: { type: "string" },
2567
2702
  originalDimensions: {
@@ -2570,11 +2705,11 @@ function createCodexImageTool(options) {
2570
2705
  properties: {
2571
2706
  width: {
2572
2707
  type: "integer",
2573
- required: true
2708
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2574
2709
  },
2575
2710
  height: {
2576
2711
  type: "integer",
2577
- required: true
2712
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2578
2713
  }
2579
2714
  }
2580
2715
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "2.1.0-beta.2",
3
+ "version": "2.1.0-beta.3",
4
4
  "description": "Use ChatGPT and Codex subscriptions in DeepSeek Harness with OAuth, quota, safe resets, web search, images, and Fast mode",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",