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

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,109 @@ 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
+ "ellipse",
599
+ "polygon",
600
+ "bezier",
601
+ "eraser"
602
+ ]
603
+ },
604
+ ...style,
605
+ action: {
606
+ type: "string",
607
+ enum: [
608
+ "update",
609
+ "duplicate",
610
+ "delete",
611
+ "add",
612
+ "select",
613
+ "rename",
614
+ "visible",
615
+ "up",
616
+ "down",
617
+ "clear"
618
+ ]
619
+ },
620
+ value: string,
621
+ ratio: {
622
+ type: "string",
623
+ enum: [
624
+ "1:1",
625
+ "4:3",
626
+ "3:4",
627
+ "16:9",
628
+ "9:16"
629
+ ]
630
+ },
631
+ patch: object(style),
632
+ transform: object({
633
+ dx: number,
634
+ dy: number,
635
+ scaleX: number,
636
+ scaleY: number
637
+ })
638
+ })
639
+ };
640
+ //#endregion
523
641
  //#region src/sketch-agent-tool.js
524
642
  function createSketchAgentTool(bridge, attachments) {
525
643
  return defineTool({
526
644
  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.",
645
+ 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
646
  parameters: {
529
647
  action: {
530
648
  type: "string",
@@ -533,28 +651,45 @@ function createSketchAgentTool(bridge, attachments) {
533
651
  "inspect",
534
652
  "apply",
535
653
  "preview",
536
- "save"
654
+ "save",
655
+ "finish"
537
656
  ]
538
657
  },
658
+ runId: {
659
+ type: "string",
660
+ description: "From inspect; required for all other actions. Never reuse a stopped run."
661
+ },
539
662
  documentId: {
540
663
  type: "string",
541
664
  description: "From inspect; required except for inspect."
542
665
  },
543
666
  revision: {
544
667
  type: "integer",
545
- description: "From latest response; required for apply/save."
668
+ description: "From latest response; required for apply/save/finish."
546
669
  },
547
670
  requestId: {
548
671
  type: "string",
549
- description: "Unique id for apply/save; exact retries are deduplicated."
672
+ description: "Unique id for apply/save/finish; exact retries are deduplicated. After timeout inspect recentRequests before repeating a write."
550
673
  },
551
674
  commands: {
552
- type: "string",
553
- description: "JSON array of native commands described by inspect. Required for apply."
675
+ oneOf: [sketchCommandArray, { type: "string" }],
676
+ 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
677
  },
555
678
  name: {
556
679
  type: "string",
557
- description: "Draft name for save."
680
+ description: "Draft name for save/finish."
681
+ },
682
+ offset: {
683
+ type: "integer",
684
+ description: "inspect only: object list offset, default 0. Follow nextOffset for further pages."
685
+ },
686
+ objectId: {
687
+ type: "string",
688
+ description: "inspect only: return full editable geometry for this object, in layer (defaults to active layer)."
689
+ },
690
+ layer: {
691
+ type: "integer",
692
+ description: "inspect only: layer containing objectId."
558
693
  }
559
694
  },
560
695
  timeoutMs: 25e3,
@@ -564,9 +699,10 @@ function createSketchAgentTool(bridge, attachments) {
564
699
  if (typeof sessionId !== "string") throw Error("A session-owned sketch call is required");
565
700
  const request = { ...args };
566
701
  if (args.action === "apply") try {
567
- request.commands = JSON.parse(args.commands);
702
+ request.commands = typeof args.commands === "string" ? JSON.parse(args.commands) : args.commands;
703
+ if (!Array.isArray(request.commands)) throw Error();
568
704
  } catch {
569
- throw Error("commands must be a JSON array");
705
+ throw Error("commands must be a native array or JSON array string");
570
706
  }
571
707
  const value = await bridge.request(sessionId, request, exec.signal);
572
708
  if (value.png) {
@@ -1835,7 +1971,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
1835
1971
  Object.freeze(["0.82.1", "0.85.1"]);
1836
1972
  //#endregion
1837
1973
  //#region src/version.js
1838
- const PACKAGE_VERSION = "2.1.0-beta.2";
1974
+ const PACKAGE_VERSION = "2.1.0-beta.4";
1839
1975
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
1840
1976
  //#endregion
1841
1977
  //#region src/model-catalog.js
@@ -2498,7 +2634,7 @@ function createCodexImageTool(options) {
2498
2634
  const attachments = options.attachments;
2499
2635
  return defineTool({
2500
2636
  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.",
2637
+ 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
2638
  parameters: {
2503
2639
  model: {
2504
2640
  type: "string",
@@ -2537,7 +2673,7 @@ function createCodexImageTool(options) {
2537
2673
  },
2538
2674
  referenceImages: {
2539
2675
  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.",
2676
+ 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
2677
  items: {
2542
2678
  type: "object",
2543
2679
  additionalProperties: false,
@@ -2549,19 +2685,19 @@ function createCodexImageTool(options) {
2549
2685
  },
2550
2686
  mediaType: {
2551
2687
  type: "string",
2552
- required: true
2688
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2553
2689
  },
2554
2690
  bytes: {
2555
2691
  type: "integer",
2556
- required: true
2692
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2557
2693
  },
2558
2694
  width: {
2559
2695
  type: "integer",
2560
- required: true
2696
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2561
2697
  },
2562
2698
  height: {
2563
2699
  type: "integer",
2564
- required: true
2700
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2565
2701
  },
2566
2702
  name: { type: "string" },
2567
2703
  originalDimensions: {
@@ -2570,11 +2706,11 @@ function createCodexImageTool(options) {
2570
2706
  properties: {
2571
2707
  width: {
2572
2708
  type: "integer",
2573
- required: true
2709
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2574
2710
  },
2575
2711
  height: {
2576
2712
  type: "integer",
2577
- required: true
2713
+ ...typeof options.getSessionMessages !== "function" ? { required: true } : {}
2578
2714
  }
2579
2715
  }
2580
2716
  }
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.4",
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",