dsh-codex-subscription 1.13.1 → 1.14.1
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/DIRECTORY.md +1 -1
- package/README.en.md +35 -27
- package/README.md +35 -25
- package/THIRD_PARTY_NOTICES.md +1 -0
- package/lib/client.js +990 -297
- package/lib/index.js +99 -13
- package/package.json +1 -2
- package/AGENTS.md +0 -93
package/lib/index.js
CHANGED
|
@@ -1303,7 +1303,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
|
|
|
1303
1303
|
}
|
|
1304
1304
|
//#endregion
|
|
1305
1305
|
//#region src/version.js
|
|
1306
|
-
const PACKAGE_VERSION = "1.
|
|
1306
|
+
const PACKAGE_VERSION = "1.14.1";
|
|
1307
1307
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
1308
1308
|
//#endregion
|
|
1309
1309
|
//#region src/model-catalog.js
|
|
@@ -1637,6 +1637,10 @@ const PNG_SIGNATURE = Buffer.from([
|
|
|
1637
1637
|
26,
|
|
1638
1638
|
10
|
|
1639
1639
|
]);
|
|
1640
|
+
const FULL_ATTACHMENT_ID = /^sha256:[0-9a-f]{64}$/u;
|
|
1641
|
+
const BARE_ATTACHMENT_DIGEST = /^[0-9a-f]{64}$/iu;
|
|
1642
|
+
const PATH_LIKE_ATTACHMENT_ID = /[\\/]/u;
|
|
1643
|
+
const FILE_NAME_ATTACHMENT_ID = /\.[A-Za-z0-9]{1,16}$/u;
|
|
1640
1644
|
const record$2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1641
1645
|
const nonEmpty = (value) => typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
1642
1646
|
function normalizeImageOptions(args) {
|
|
@@ -1706,22 +1710,63 @@ function decodeCodexPng(value, maximumBytes) {
|
|
|
1706
1710
|
return new Uint8Array(data);
|
|
1707
1711
|
}
|
|
1708
1712
|
function imageReference(value) {
|
|
1713
|
+
const originalDimensions = record$2(value.originalDimensions) ? {
|
|
1714
|
+
width: value.originalDimensions.width,
|
|
1715
|
+
height: value.originalDimensions.height
|
|
1716
|
+
} : void 0;
|
|
1709
1717
|
return {
|
|
1710
1718
|
attachmentId: value.attachmentId,
|
|
1711
1719
|
mediaType: value.mediaType,
|
|
1712
1720
|
bytes: value.bytes,
|
|
1713
1721
|
width: value.width,
|
|
1714
1722
|
height: value.height,
|
|
1715
|
-
...value.name === void 0 ? {} : { name: value.name }
|
|
1723
|
+
...value.name === void 0 ? {} : { name: value.name },
|
|
1724
|
+
...originalDimensions === void 0 ? {} : { originalDimensions }
|
|
1716
1725
|
};
|
|
1717
1726
|
}
|
|
1727
|
+
function normalizeAttachmentId(value) {
|
|
1728
|
+
if (typeof value !== "string") return void 0;
|
|
1729
|
+
if (FULL_ATTACHMENT_ID.test(value)) return value;
|
|
1730
|
+
const bare = BARE_ATTACHMENT_DIGEST.exec(value);
|
|
1731
|
+
return bare === null ? void 0 : `sha256:${bare[0].toLowerCase()}`;
|
|
1732
|
+
}
|
|
1733
|
+
function invalidAttachmentId(value) {
|
|
1734
|
+
const attachmentId = value?.attachmentId;
|
|
1735
|
+
if (typeof attachmentId === "string" && (PATH_LIKE_ATTACHMENT_ID.test(attachmentId) || FILE_NAME_ATTACHMENT_ID.test(attachmentId))) throw new Error("referenceImages attachmentId is a file path or filename; call read_image on that file and retry with its complete sha256:<64 lowercase hex> attachment reference. Do not omit referenceImages or fall back to new image generation.");
|
|
1736
|
+
throw new Error("referenceImages attachmentId must be sha256:<64 lowercase hex> copied from an image block or read_image result. Do not omit referenceImages or fall back to new image generation.");
|
|
1737
|
+
}
|
|
1718
1738
|
function referenceOf(value, attachments) {
|
|
1719
|
-
|
|
1720
|
-
|
|
1739
|
+
const attachmentId = normalizeAttachmentId(value?.attachmentId);
|
|
1740
|
+
if (attachmentId === void 0) invalidAttachmentId(value);
|
|
1741
|
+
if (!record$2(value) || !attachments.imageLimits.mediaTypes.includes(value.mediaType) || !Number.isSafeInteger(value.bytes) || value.bytes <= 0 || !Number.isSafeInteger(value.width) || value.width <= 0 || !Number.isSafeInteger(value.height) || value.height <= 0 || value.name !== void 0 && (typeof value.name !== "string" || value.name.length > 256) || value.originalDimensions !== void 0 && (!record$2(value.originalDimensions) || !Number.isSafeInteger(value.originalDimensions.width) || value.originalDimensions.width <= 0 || !Number.isSafeInteger(value.originalDimensions.height) || value.originalDimensions.height <= 0)) throw new Error("referenceImages contains an invalid image reference");
|
|
1742
|
+
return imageReference({
|
|
1743
|
+
...value,
|
|
1744
|
+
attachmentId
|
|
1745
|
+
});
|
|
1721
1746
|
}
|
|
1722
|
-
|
|
1747
|
+
function sessionImageReferences(messages) {
|
|
1748
|
+
const references = /* @__PURE__ */ new Map();
|
|
1749
|
+
const visit = (content) => {
|
|
1750
|
+
if (!Array.isArray(content)) return;
|
|
1751
|
+
for (const block of content) if (block?.type === "image" && record$2(block.attachment)) {
|
|
1752
|
+
const id = normalizeAttachmentId(block.attachment.attachmentId);
|
|
1753
|
+
if (id !== void 0) references.set(id, block.attachment);
|
|
1754
|
+
} else if (block?.type === "tool-result") visit(block.content);
|
|
1755
|
+
};
|
|
1756
|
+
for (const message of messages ?? []) visit(message?.content);
|
|
1757
|
+
return references;
|
|
1758
|
+
}
|
|
1759
|
+
async function editImages(values, attachments, signal, messages) {
|
|
1723
1760
|
if (!Array.isArray(values) || values.length === 0 || values.length > MAX_REFERENCE_IMAGES) throw new Error(`referenceImages must contain between 1 and ${MAX_REFERENCE_IMAGES} images`);
|
|
1724
|
-
const
|
|
1761
|
+
const available = messages === void 0 ? void 0 : sessionImageReferences(messages);
|
|
1762
|
+
const references = values.map((value) => {
|
|
1763
|
+
const id = normalizeAttachmentId(value?.attachmentId);
|
|
1764
|
+
if (id === void 0) invalidAttachmentId(value);
|
|
1765
|
+
if (available === void 0) return referenceOf(value, attachments);
|
|
1766
|
+
const selected = available.get(id);
|
|
1767
|
+
if (selected === void 0) throw new Error("The selected image attachment cannot be found in the current session. Call read_image on the intended image and retry with its returned reference. Do not omit referenceImages or substitute another image.");
|
|
1768
|
+
return referenceOf(selected, attachments);
|
|
1769
|
+
});
|
|
1725
1770
|
if (new Set(references.map((value) => value.attachmentId)).size !== references.length) throw new Error("referenceImages must not contain duplicates");
|
|
1726
1771
|
const images = [];
|
|
1727
1772
|
let totalBytes = 0;
|
|
@@ -1734,9 +1779,10 @@ async function editImages(values, attachments, signal) {
|
|
|
1734
1779
|
return images;
|
|
1735
1780
|
}
|
|
1736
1781
|
function imageContent(value) {
|
|
1782
|
+
const label = typeof value.size === "string" && value.size.length > 0 ? `Generated a ${value.size} image.` : "Generated an image.";
|
|
1737
1783
|
return [{
|
|
1738
1784
|
type: "text",
|
|
1739
|
-
text:
|
|
1785
|
+
text: value.localPath === void 0 ? label : `${label}\nOriginal PNG saved on the DSH host at: ${JSON.stringify(value.localPath)}. Read this file or copy it to the workspace with a .png extension; this host path is not a browser URL.`
|
|
1740
1786
|
}, {
|
|
1741
1787
|
type: "image",
|
|
1742
1788
|
attachment: imageReference(value.image)
|
|
@@ -1773,7 +1819,21 @@ function imageOutputSchema() {
|
|
|
1773
1819
|
type: "integer",
|
|
1774
1820
|
required: true
|
|
1775
1821
|
},
|
|
1776
|
-
name: { type: "string" }
|
|
1822
|
+
name: { type: "string" },
|
|
1823
|
+
originalDimensions: {
|
|
1824
|
+
type: "object",
|
|
1825
|
+
additionalProperties: false,
|
|
1826
|
+
properties: {
|
|
1827
|
+
width: {
|
|
1828
|
+
type: "integer",
|
|
1829
|
+
required: true
|
|
1830
|
+
},
|
|
1831
|
+
height: {
|
|
1832
|
+
type: "integer",
|
|
1833
|
+
required: true
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1777
1837
|
}
|
|
1778
1838
|
},
|
|
1779
1839
|
original: {
|
|
@@ -1813,6 +1873,11 @@ function imageOutputSchema() {
|
|
|
1813
1873
|
}
|
|
1814
1874
|
},
|
|
1815
1875
|
background: { type: "string" },
|
|
1876
|
+
localPath: {
|
|
1877
|
+
type: "string",
|
|
1878
|
+
required: true,
|
|
1879
|
+
description: "Absolute path to the original PNG on the DSH host."
|
|
1880
|
+
},
|
|
1816
1881
|
quality: { type: "string" },
|
|
1817
1882
|
size: { type: "string" }
|
|
1818
1883
|
}
|
|
@@ -1835,7 +1900,7 @@ function createCodexImageTool(options) {
|
|
|
1835
1900
|
const attachments = options.attachments;
|
|
1836
1901
|
return defineTool({
|
|
1837
1902
|
name: CODEX_IMAGE_TOOL_NAME,
|
|
1838
|
-
description: "Create a new image or explicitly edit selected prior images using the signed-in Codex subscription. Omit referenceImages for a completely new image. Include only the exact prior image references the user asked to edit; never assume every image in the conversation is a reference.",
|
|
1903
|
+
description: "Create a new image or explicitly edit selected prior images using the signed-in Codex subscription. Omit referenceImages only for a completely new image. For an edit, copy each complete image reference from the session image block or read_image result, including attachmentId in the exact form sha256:<64 lowercase hex>; never use a workspace path, absolute path, or filename, and do not omit the references to turn an edit into text-to-image generation. A bare 64-character hex digest is accepted and normalized to sha256:<64 lowercase hex>. If a reference is unavailable, call read_image and retry with its returned reference. Include only the exact prior image references the user asked to edit; never assume every image in the conversation is a reference. For annotation-guided edits, include both the named clean source and its numbered location reference, and preserve the numbered coordinates and requested changes in the prompt. The location-reference markers are guidance only and must not appear in the result. If those references cannot be identified, do not substitute unrelated images or silently ignore the annotations.",
|
|
1839
1904
|
parameters: {
|
|
1840
1905
|
prompt: {
|
|
1841
1906
|
type: "string",
|
|
@@ -1867,14 +1932,15 @@ function createCodexImageTool(options) {
|
|
|
1867
1932
|
},
|
|
1868
1933
|
referenceImages: {
|
|
1869
1934
|
type: "array",
|
|
1870
|
-
description: "Optional explicit references to 1-5 prior images to edit. Omit for a new image.",
|
|
1935
|
+
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.",
|
|
1871
1936
|
items: {
|
|
1872
1937
|
type: "object",
|
|
1873
1938
|
additionalProperties: false,
|
|
1874
1939
|
properties: {
|
|
1875
1940
|
attachmentId: {
|
|
1876
1941
|
type: "string",
|
|
1877
|
-
required: true
|
|
1942
|
+
required: true,
|
|
1943
|
+
description: "Copy the complete attachmentId from the image block or read_image result: sha256:<64 lowercase hex>. Never pass a workspace path, absolute path, or filename. A bare 64-character hex digest is accepted and normalized to sha256:<64 lowercase hex>."
|
|
1878
1944
|
},
|
|
1879
1945
|
mediaType: {
|
|
1880
1946
|
type: "string",
|
|
@@ -1892,7 +1958,21 @@ function createCodexImageTool(options) {
|
|
|
1892
1958
|
type: "integer",
|
|
1893
1959
|
required: true
|
|
1894
1960
|
},
|
|
1895
|
-
name: { type: "string" }
|
|
1961
|
+
name: { type: "string" },
|
|
1962
|
+
originalDimensions: {
|
|
1963
|
+
type: "object",
|
|
1964
|
+
additionalProperties: false,
|
|
1965
|
+
properties: {
|
|
1966
|
+
width: {
|
|
1967
|
+
type: "integer",
|
|
1968
|
+
required: true
|
|
1969
|
+
},
|
|
1970
|
+
height: {
|
|
1971
|
+
type: "integer",
|
|
1972
|
+
required: true
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1896
1976
|
}
|
|
1897
1977
|
}
|
|
1898
1978
|
}
|
|
@@ -1920,7 +2000,8 @@ function createCodexImageTool(options) {
|
|
|
1920
2000
|
if (!attachments.imageLimits.mediaTypes.includes("image/png")) throw new Error("This DSH installation does not accept PNG image attachments");
|
|
1921
2001
|
const maximumBytes = Math.min(attachments.imageLimits.maxImageBytes, attachments.imageLimits.maxMessageImageBytes);
|
|
1922
2002
|
const editing = args.referenceImages !== void 0;
|
|
1923
|
-
const
|
|
2003
|
+
const sessionMessages = editing && typeof options.getSessionMessages === "function" ? await options.getSessionMessages(exec.agent?.id) : void 0;
|
|
2004
|
+
const images = editing ? await editImages(args.referenceImages, attachments, exec.signal, sessionMessages ?? (options.getSessionMessages ? [] : void 0)) : void 0;
|
|
1924
2005
|
let response;
|
|
1925
2006
|
try {
|
|
1926
2007
|
response = await fetchImage(editing ? CODEX_IMAGE_EDIT_URL : CODEX_IMAGE_GENERATION_URL, {
|
|
@@ -1973,6 +2054,7 @@ function createCodexImageTool(options) {
|
|
|
1973
2054
|
const result = {
|
|
1974
2055
|
image: imageReference(ref),
|
|
1975
2056
|
original,
|
|
2057
|
+
localPath: options.originalImages.originalPath(original.assetId),
|
|
1976
2058
|
...metadata.background === void 0 ? {} : { background: metadata.background },
|
|
1977
2059
|
...metadata.quality === void 0 ? {} : { quality: metadata.quality },
|
|
1978
2060
|
...metadata.size === void 0 ? {} : { size: metadata.size }
|
|
@@ -2045,6 +2127,9 @@ var OriginalImageStore = class {
|
|
|
2045
2127
|
if (!ORIGINAL_IMAGE_ID_PATTERN.test(assetId)) throw new TypeError("invalid original image asset id");
|
|
2046
2128
|
return join(this.root, assetId.slice(4, 6), assetId);
|
|
2047
2129
|
}
|
|
2130
|
+
originalPath(assetId) {
|
|
2131
|
+
return join(this.directory(assetId), "original");
|
|
2132
|
+
}
|
|
2048
2133
|
async save(sessionId, data, name = "codex-generated-original.png") {
|
|
2049
2134
|
if (!validSessionId(sessionId) || !(data instanceof Uint8Array) || data.byteLength === 0 || data.byteLength > 48 * 1024 * 1024) throw new TypeError("invalid original image input");
|
|
2050
2135
|
const { width, height } = pngDimensions(data);
|
|
@@ -3294,6 +3379,7 @@ function apply(ctx) {
|
|
|
3294
3379
|
getAuth: resolveAuth,
|
|
3295
3380
|
readCredential: (options) => store.read(PROVIDER, options),
|
|
3296
3381
|
attachments: ctx.attachments,
|
|
3382
|
+
getSessionMessages: (sessionId) => ctx.get?.("sessions")?.get?.(sessionId)?.deriveMessages?.() ?? [],
|
|
3297
3383
|
originalImages,
|
|
3298
3384
|
fetch: (input, init) => network.fetch("image", input, init)
|
|
3299
3385
|
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.1",
|
|
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",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"README.en.md",
|
|
18
18
|
"README.zh-CN.md",
|
|
19
19
|
"DIRECTORY.md",
|
|
20
|
-
"AGENTS.md",
|
|
21
20
|
"compatibility.json",
|
|
22
21
|
"LICENSE",
|
|
23
22
|
"SECURITY.md",
|
package/AGENTS.md
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Agent installation guide
|
|
2
|
-
|
|
3
|
-
Use this guide when a user asks an Agent to install, update, verify, or remove
|
|
4
|
-
`dsh-codex-subscription` in a selected DeepSeek Harness profile.
|
|
5
|
-
|
|
6
|
-
## Safety
|
|
7
|
-
|
|
8
|
-
- Confirm the target DSH installation and profile. Use `web` only when it is the user's target.
|
|
9
|
-
- Use the exact `1.13.1` package below; do not install a moving branch.
|
|
10
|
-
- Never print OAuth credentials, account IDs, authorization callbacks, or credential-store contents.
|
|
11
|
-
- Preserve the DSH profile, unrelated plugins, sessions, and saved sign-in.
|
|
12
|
-
- Do not start, stop, or restart DSH without explicit permission.
|
|
13
|
-
- If more than one DSH installation exists, ask which one is the target before changing it.
|
|
14
|
-
|
|
15
|
-
## Locate DSH
|
|
16
|
-
|
|
17
|
-
On Windows, check the standard DSH and official npm entry points without recursively scanning disks:
|
|
18
|
-
|
|
19
|
-
```powershell
|
|
20
|
-
Get-Command dsh -ErrorAction SilentlyContinue
|
|
21
|
-
Get-Command npx -ErrorAction SilentlyContinue
|
|
22
|
-
Get-CimInstance Win32_Process -Filter "Name = 'node.exe'" |
|
|
23
|
-
Where-Object { $_.CommandLine -match '@deepseek-ai[\\/]dsh[\\/]lib[\\/]bin\.js' } |
|
|
24
|
-
Select-Object ExecutablePath, CommandLine
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
DSH-Portable exposes the same standard `dsh plugin` contract. Missing system pnpm is normal; do not
|
|
28
|
-
install it globally for this plugin. If several targets remain possible, stop and ask the user which one
|
|
29
|
-
to change.
|
|
30
|
-
|
|
31
|
-
## Install or update
|
|
32
|
-
|
|
33
|
-
For an official DSH installation run through npm, keep the complete `npx` prefix because the official
|
|
34
|
-
run command does not create a global `dsh` command:
|
|
35
|
-
|
|
36
|
-
```sh
|
|
37
|
-
npx -y @deepseek-ai/dsh@0.1.2-rc.1 plugin --profile web add dsh-codex-subscription@1.13.1
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
With an existing global `dsh` command:
|
|
41
|
-
|
|
42
|
-
```sh
|
|
43
|
-
dsh plugin --profile web add dsh-codex-subscription@1.13.1
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Use the same `add` command to update or repair. This is the complete package-changing operation.
|
|
47
|
-
Do not download pnpm, create a second package store, save profile snapshots, add a resident manager,
|
|
48
|
-
or restart DSH automatically. The DSH CLI owns package resolution, locking, and profile composition.
|
|
49
|
-
|
|
50
|
-
## Verify
|
|
51
|
-
|
|
52
|
-
Use the same executable selected above:
|
|
53
|
-
|
|
54
|
-
```sh
|
|
55
|
-
dsh plugin --profile web list dsh-codex-subscription --depth 0
|
|
56
|
-
dsh --profile web --dump-config
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh@0.1.2-rc.1` in place of `dsh`.
|
|
60
|
-
|
|
61
|
-
1. `dsh-codex-subscription` version `1.13.1` appears exactly once.
|
|
62
|
-
2. `codex-subscription` appears exactly once in the composed config.
|
|
63
|
-
3. No unrelated plugin or profile was changed and DSH was not restarted.
|
|
64
|
-
|
|
65
|
-
With permission to restart DSH, open **Settings -> Codex** and verify the settings page loads. Confirm
|
|
66
|
-
that search offers **Auto**, **DSH default**, and **Codex subscription**, the composer quota switch defaults
|
|
67
|
-
to off, and `codex_image_generate` is available. Do not consume quota merely to test installation unless
|
|
68
|
-
the user explicitly asks for a live model, search, or image-generation check.
|
|
69
|
-
|
|
70
|
-
## Uninstall
|
|
71
|
-
|
|
72
|
-
```sh
|
|
73
|
-
dsh plugin --profile web remove dsh-codex-subscription
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
For the official npm route:
|
|
77
|
-
|
|
78
|
-
```sh
|
|
79
|
-
npx -y @deepseek-ai/dsh@0.1.2-rc.1 plugin --profile web remove dsh-codex-subscription
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
Uninstall removes only this plugin. It must preserve the profile, sessions, other plugins, and saved
|
|
83
|
-
ChatGPT sign-in. Signing out is a separate action and requires explicit permission.
|
|
84
|
-
|
|
85
|
-
## Failure handling
|
|
86
|
-
|
|
87
|
-
Distinguish command discovery, network, HTTP/TLS, package-manager, profile-lock, version, and peer
|
|
88
|
-
dependency failures. Do not disable TLS validation, delete a lock owned by a live process, install a
|
|
89
|
-
second package manager, wipe a profile, expose credentials, or switch to another paid route.
|
|
90
|
-
|
|
91
|
-
On failure, report the sanitized command error, DSH version, selected profile, requested plugin version,
|
|
92
|
-
installation mode, what changed, and what remains unverified. A successful CLI exit is not live UI
|
|
93
|
-
acceptance.
|