dsh-lcx-codex 0.4.3 → 0.5.0-pre.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/README.md +95 -60
- package/lib/abort-error.js +47 -0
- package/lib/client.js +597 -505
- package/lib/dsh-compat.js +37 -0
- package/lib/dsh-responses.js +92 -48
- package/lib/index.js +174 -105
- package/lib/invocation-policy-scope.js +4 -8
- package/lib/native-checkpoint.js +172 -80
- package/lib/pi-responses-runtime.js +252 -98
- package/lib/pi086-responses-allowlist.js +131 -0
- package/lib/responses-request.js +2 -2
- package/lib/responses-stream.js +62 -11
- package/lib/route.js +23 -32
- package/lib/search-accounting.js +22 -6
- package/lib/search-usage.js +32 -18
- package/lib/service-mutex.js +4 -8
- package/lib/token-budget.js +15 -21
- package/lib/transport.js +6 -6
- package/lib/types/client/search-media.d.ts +11 -2
- package/lib/types/index.d.ts +71 -43
- package/lib/web-search-alpha-history.js +62 -0
- package/lib/web-search-alpha.js +141 -124
- package/lib/web-search-capability.js +1 -1
- package/lib/web-search-hosted.js +29 -17
- package/lib/web-search-ref-store.js +27 -5
- package/package.json +41 -27
package/lib/web-search-hosted.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { outputDomains, outputLineRange, parseWebRunOutput } from "./web-run-output.js";
|
|
2
|
-
export const HOSTED_SEARCH_PARAMETERS = { type: "object", properties: { query: { type: "string", description: "Advanced Responses Hosted Web Search query. Use DSH web_search for ordinary searches." }, searchContextSize: { type: "string", enum: ["low", "medium", "high"] }, allowedDomains: { type: "array", items: { type: "string" } }, blockedDomains: { type: "array", items: { type: "string" } }, userLocation: { type: "object", properties: { country: { type: "string" }, city: { type: "string" }, region: { type: "string" }, timezone: { type: "string" } }, additionalProperties: false }, externalWebAccess: { type: "boolean" }, returnTokenBudget: { type: "string", enum: ["default", "unlimited"] }, searchContentTypes: { type: "array", items: { type: "string", enum: ["text", "image"] } }, imageSettings: { type: "object", properties: { maxResults: { type: "integer" }, caption: { type: "boolean" } }, additionalProperties: false } }, required: ["query"], additionalProperties: false };
|
|
2
|
+
export const HOSTED_SEARCH_PARAMETERS = { type: "object", properties: { query: { type: "string", description: "Advanced Responses Hosted Web Search query. Use DSH web_search for ordinary searches." }, searchContextSize: { type: "string", enum: ["low", "medium", "high"] }, allowedDomains: { type: "array", items: { type: "string" }, description: "Optional allow filter. Omit or use [] for no filter; only nonempty lists are sent." }, blockedDomains: { type: "array", items: { type: "string" }, description: "Optional block filter. Omit or use [] for no filter; only nonempty lists are sent." }, userLocation: { type: "object", properties: { country: { type: "string" }, city: { type: "string" }, region: { type: "string" }, timezone: { type: "string" } }, additionalProperties: false }, externalWebAccess: { type: "boolean" }, returnTokenBudget: { type: "string", enum: ["default", "unlimited"] }, searchContentTypes: { type: "array", items: { type: "string", enum: ["text", "image"] }, description: "Optional content types. Omit unless image results are needed; [] means no explicit content-type override." }, imageSettings: { type: "object", description: "Optional image settings. Omit unless searchContentTypes includes image; ignored (after validation) without image search.", properties: { maxResults: { type: "integer" }, caption: { type: "boolean" } }, additionalProperties: false } }, required: ["query"], additionalProperties: false };
|
|
3
3
|
export const HOSTED_SEARCH_OUTPUT = { type: "object", properties: { mode: { type: "string", enum: ["hosted"] }, action: { type: "string" }, emulation: { type: "string", enum: ["native"] }, content: { type: "string" }, sources: { type: "array", items: { type: "object" } }, citations: { type: "array", items: { type: "object" } }, images: { type: "array", items: { type: "object" } }, warnings: { type: "array", items: { type: "string" } }, outputBlocks: { type: "array", items: { type: "object" } }, domains: { type: "array", items: { type: "string" } }, lineRange: { type: "object" }, requestId: { type: "string" }, responseId: { type: "string" }, retrievedAt: { type: "string" }, truncated: { type: "boolean" }, usage: { type: "object", properties: { inputTokens: { type: "number" }, outputTokens: { type: "number" }, totalTokens: { type: "number" }, cachedInputTokens: { type: "number" }, actionCount: { type: "number" }, serverWebSearchCalls: { type: "number" } }, additionalProperties: false } }, required: ["mode", "action", "emulation", "content", "sources", "citations", "images", "warnings", "requestId", "retrievedAt", "truncated"], additionalProperties: false };
|
|
4
4
|
function failure(message, code = "WEB_INVALID_REQUEST") { return Object.assign(new Error(message), { code }); }
|
|
5
5
|
function isRecord(value) { return value !== null && typeof value === "object" && !Array.isArray(value); }
|
|
@@ -16,8 +16,10 @@ catch {
|
|
|
16
16
|
function normalizeDomains(value, field) {
|
|
17
17
|
if (value === undefined)
|
|
18
18
|
return undefined;
|
|
19
|
-
if (!isStringArray(value) || value.length
|
|
20
|
-
throw failure(`websearch_gpt_advanced.${field} must contain
|
|
19
|
+
if (!isStringArray(value) || value.length > 100)
|
|
20
|
+
throw failure(`websearch_gpt_advanced.${field} must contain 0 to 100 domains`);
|
|
21
|
+
if (value.length === 0)
|
|
22
|
+
return undefined;
|
|
21
23
|
const result = value.map((item) => {
|
|
22
24
|
const domain = item.trim().toLowerCase();
|
|
23
25
|
if (!domain || domain.length > 253 || domain.includes("/") || domain.includes(":") || domain.endsWith(".") || domain.split(".").length < 2)
|
|
@@ -32,7 +34,7 @@ function normalizeLocation(value) {
|
|
|
32
34
|
if (!isRecord(value))
|
|
33
35
|
throw failure("websearch_gpt_advanced.userLocation must be an object");
|
|
34
36
|
const result = {};
|
|
35
|
-
if (value.country !== undefined) {
|
|
37
|
+
if (value.country !== undefined && !(typeof value.country === "string" && !value.country.trim())) {
|
|
36
38
|
if (typeof value.country !== "string" || !/^[a-z]{2}$/iu.test(value.country.trim()))
|
|
37
39
|
throw failure("userLocation.country must be ISO alpha-2");
|
|
38
40
|
result.country = value.country.trim().toUpperCase();
|
|
@@ -40,11 +42,13 @@ function normalizeLocation(value) {
|
|
|
40
42
|
for (const field of ["city", "region"])
|
|
41
43
|
if (value[field] !== undefined) {
|
|
42
44
|
const text = value[field];
|
|
43
|
-
if (typeof text
|
|
45
|
+
if (typeof text === "string" && !text.trim())
|
|
46
|
+
continue;
|
|
47
|
+
if (typeof text !== "string" || text.length > 200)
|
|
44
48
|
throw failure(`userLocation.${field} is invalid`);
|
|
45
49
|
result[field] = text.trim();
|
|
46
50
|
}
|
|
47
|
-
if (value.timezone !== undefined) {
|
|
51
|
+
if (value.timezone !== undefined && !(typeof value.timezone === "string" && !value.timezone.trim())) {
|
|
48
52
|
if (typeof value.timezone !== "string")
|
|
49
53
|
throw failure("userLocation.timezone must be an IANA timezone");
|
|
50
54
|
try {
|
|
@@ -55,9 +59,7 @@ function normalizeLocation(value) {
|
|
|
55
59
|
}
|
|
56
60
|
result.timezone = value.timezone;
|
|
57
61
|
}
|
|
58
|
-
|
|
59
|
-
throw failure("userLocation is empty");
|
|
60
|
-
return result;
|
|
62
|
+
return Object.keys(result).length ? result : undefined;
|
|
61
63
|
}
|
|
62
64
|
export function normalizeHostedSearchArgs(args) {
|
|
63
65
|
if (!isRecord(args) || typeof args.query !== "string" || !args.query.trim())
|
|
@@ -79,8 +81,11 @@ export function normalizeHostedSearchArgs(args) {
|
|
|
79
81
|
result.blockedDomains = blockedDomains;
|
|
80
82
|
if (allowedDomains && blockedDomains && allowedDomains.some((domain) => blockedDomains.includes(domain)))
|
|
81
83
|
throw failure("domain filters conflict");
|
|
82
|
-
if (args.userLocation !== undefined)
|
|
83
|
-
|
|
84
|
+
if (args.userLocation !== undefined) {
|
|
85
|
+
const userLocation = normalizeLocation(args.userLocation);
|
|
86
|
+
if (userLocation)
|
|
87
|
+
result.userLocation = userLocation;
|
|
88
|
+
}
|
|
84
89
|
if (args.externalWebAccess !== undefined) {
|
|
85
90
|
if (typeof args.externalWebAccess !== "boolean")
|
|
86
91
|
throw failure("externalWebAccess must be boolean");
|
|
@@ -92,17 +97,23 @@ export function normalizeHostedSearchArgs(args) {
|
|
|
92
97
|
result.returnTokenBudget = args.returnTokenBudget;
|
|
93
98
|
}
|
|
94
99
|
if (args.searchContentTypes !== undefined) {
|
|
95
|
-
if (!isStringArray(args.searchContentTypes) ||
|
|
100
|
+
if (!isStringArray(args.searchContentTypes) || args.searchContentTypes.length > 2 || args.searchContentTypes.some((value) => value !== "text" && value !== "image"))
|
|
96
101
|
throw failure("searchContentTypes is invalid");
|
|
97
|
-
|
|
102
|
+
if (args.searchContentTypes.length)
|
|
103
|
+
result.searchContentTypes = [...new Set(args.searchContentTypes)];
|
|
98
104
|
}
|
|
99
105
|
if (args.imageSettings !== undefined) {
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
// Always validated structurally. Without image search the object is inert model padding: it is
|
|
107
|
+
// dropped entirely, and maxResults 0 is tolerated only there. With image search, 1..100 is strict.
|
|
108
|
+
const imageSearch = result.searchContentTypes?.includes("image") === true;
|
|
109
|
+
if (!isRecord(args.imageSettings))
|
|
110
|
+
throw failure("imageSettings must be an object");
|
|
111
|
+
if (Object.keys(args.imageSettings).some((key) => key !== "maxResults" && key !== "caption"))
|
|
112
|
+
throw failure("imageSettings has unsupported fields");
|
|
102
113
|
const imageSettings = {};
|
|
103
114
|
if (args.imageSettings.maxResults !== undefined) {
|
|
104
115
|
const maxResults = args.imageSettings.maxResults;
|
|
105
|
-
if (!isInteger(maxResults) || maxResults < 1 || maxResults > 100)
|
|
116
|
+
if (!isInteger(maxResults) || maxResults < (imageSearch ? 1 : 0) || maxResults > 100)
|
|
106
117
|
throw failure("imageSettings.maxResults is invalid");
|
|
107
118
|
imageSettings.maxResults = maxResults;
|
|
108
119
|
}
|
|
@@ -111,7 +122,8 @@ export function normalizeHostedSearchArgs(args) {
|
|
|
111
122
|
throw failure("imageSettings.caption must be boolean");
|
|
112
123
|
imageSettings.caption = args.imageSettings.caption;
|
|
113
124
|
}
|
|
114
|
-
|
|
125
|
+
if (imageSearch)
|
|
126
|
+
result.imageSettings = imageSettings;
|
|
115
127
|
}
|
|
116
128
|
return result;
|
|
117
129
|
}
|
|
@@ -27,7 +27,9 @@ function validProvenance(value) {
|
|
|
27
27
|
(value.artifactFingerprint === undefined || validFingerprint(value.artifactFingerprint));
|
|
28
28
|
}
|
|
29
29
|
function validRef(refId, value) {
|
|
30
|
-
return isRecord(value) && value.refId === refId &&
|
|
30
|
+
return isRecord(value) && value.refId === refId &&
|
|
31
|
+
(value.rawRefId === undefined || (typeof value.rawRefId === "string" && value.rawRefId.length > 0)) &&
|
|
32
|
+
validHttpUrl(value.url) && validProvenance(value.provenance);
|
|
31
33
|
}
|
|
32
34
|
function validSession(value) {
|
|
33
35
|
return isRecord(value) &&
|
|
@@ -88,7 +90,7 @@ function collision(refId) {
|
|
|
88
90
|
});
|
|
89
91
|
}
|
|
90
92
|
function sameObservation(left, right) {
|
|
91
|
-
return left.refId === right.refId && left.url === right.url &&
|
|
93
|
+
return (left.rawRefId ?? left.refId) === (right.rawRefId ?? right.refId) && left.url === right.url &&
|
|
92
94
|
left.provenance.action === right.provenance.action &&
|
|
93
95
|
left.provenance.originKind === right.provenance.originKind &&
|
|
94
96
|
left.provenance.originFingerprint === right.provenance.originFingerprint &&
|
|
@@ -99,10 +101,11 @@ export class AlphaRefStore {
|
|
|
99
101
|
constructor(file) {
|
|
100
102
|
this.store = new JsonStore(file, () => ({ version: VERSION, sessions: {} }), validData, "LCX_ALPHA_REF_STORE_CORRUPT", migrateLegacyData);
|
|
101
103
|
}
|
|
102
|
-
record(sessionId, routeFingerprint, refs) {
|
|
104
|
+
record(sessionId, routeFingerprint, refs, allowAliases = false) {
|
|
103
105
|
if (typeof sessionId !== "string" || !sessionId || typeof routeFingerprint !== "string" || !routeFingerprint || !Array.isArray(refs)) {
|
|
104
106
|
throw unavailable("invalid-record");
|
|
105
107
|
}
|
|
108
|
+
const handles = {};
|
|
106
109
|
this.store.update((current) => {
|
|
107
110
|
const previous = current.sessions[sessionId];
|
|
108
111
|
const sameRoute = previous?.routeFingerprint === routeFingerprint;
|
|
@@ -122,12 +125,26 @@ export class AlphaRefStore {
|
|
|
122
125
|
...(value.url ? { url: value.url } : {}),
|
|
123
126
|
provenance: { ...value.provenance },
|
|
124
127
|
};
|
|
128
|
+
const rawHistory = Object.values(nextRefs).filter((ref) => (ref.rawRefId ?? ref.refId) === observation.refId);
|
|
129
|
+
const latest = rawHistory.at(-1);
|
|
130
|
+
if (latest && sameObservation(latest, observation)) {
|
|
131
|
+
handles[observation.refId] = latest.refId;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (accepted && !allowAliases)
|
|
135
|
+
throw collision(observation.refId);
|
|
125
136
|
if (accepted) {
|
|
126
|
-
|
|
127
|
-
|
|
137
|
+
const digest = createHash("sha256").update(JSON.stringify([observation, rawHistory.length])).digest("hex");
|
|
138
|
+
const handle = `lcx-alpha-${digest}`;
|
|
139
|
+
if (nextRefs[handle] && !sameObservation(nextRefs[handle], observation))
|
|
140
|
+
throw collision(handle);
|
|
141
|
+
nextRefs[handle] = { ...observation, refId: handle, rawRefId: observation.refId };
|
|
142
|
+
handles[observation.refId] = handle;
|
|
143
|
+
changed = true;
|
|
128
144
|
continue;
|
|
129
145
|
}
|
|
130
146
|
nextRefs[observation.refId] = observation;
|
|
147
|
+
handles[observation.refId] = observation.refId;
|
|
131
148
|
changed = true;
|
|
132
149
|
}
|
|
133
150
|
if (!changed && previous)
|
|
@@ -141,6 +158,7 @@ export class AlphaRefStore {
|
|
|
141
158
|
.slice(0, 256);
|
|
142
159
|
return { version: VERSION, sessions: Object.fromEntries(ordered) };
|
|
143
160
|
});
|
|
161
|
+
return handles;
|
|
144
162
|
}
|
|
145
163
|
assertUsable(sessionId, routeFingerprint, refId) {
|
|
146
164
|
this.store.refresh();
|
|
@@ -150,6 +168,10 @@ export class AlphaRefStore {
|
|
|
150
168
|
const ref = session?.routeFingerprint === routeFingerprint ? session.refs[refId] : undefined;
|
|
151
169
|
if (!ref)
|
|
152
170
|
throw unavailable(refId);
|
|
171
|
+
const raw = ref.rawRefId ?? ref.refId;
|
|
172
|
+
const latest = Object.values(session?.refs ?? {}).filter((other) => (other.rawRefId ?? other.refId) === raw).at(-1);
|
|
173
|
+
if (latest?.refId !== refId)
|
|
174
|
+
throw unavailable(refId);
|
|
153
175
|
return structuredClone(ref);
|
|
154
176
|
}
|
|
155
177
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-lcx-codex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0-pre.1",
|
|
4
4
|
"description": "Model-scoped DSH plugin: GPT Responses lifecycle, Native V2 compaction and Hosted/Alpha Search; Grok native Web/X Search",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -56,13 +56,14 @@
|
|
|
56
56
|
"inject": [
|
|
57
57
|
"@deepseek-ai/dsh-client-ui-chat",
|
|
58
58
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
59
|
-
"@deepseek-ai/dsh-client-ui-
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager",
|
|
60
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
60
61
|
]
|
|
61
62
|
}
|
|
62
63
|
},
|
|
63
64
|
"devDependencies": {
|
|
64
|
-
"@deepseek-ai/dsh": "0.
|
|
65
|
-
"@earendil-works/pi-ai": "0.
|
|
65
|
+
"@deepseek-ai/dsh": "0.2.0-rc.2",
|
|
66
|
+
"@earendil-works/pi-ai": "0.87.1",
|
|
66
67
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
67
68
|
"@types/node": "^22.20.0",
|
|
68
69
|
"@types/react": "~18.3.1",
|
|
@@ -72,30 +73,36 @@
|
|
|
72
73
|
},
|
|
73
74
|
"peerDependencies": {
|
|
74
75
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
75
|
-
"@deepseek-ai/
|
|
76
|
-
"@deepseek-ai/dsh-
|
|
77
|
-
"@deepseek-ai/dsh-
|
|
78
|
-
"@deepseek-ai/dsh-client-
|
|
79
|
-
"@deepseek-ai/dsh-client-
|
|
80
|
-
"@deepseek-ai/dsh-client-
|
|
81
|
-
"@deepseek-ai/dsh-client-ui-
|
|
82
|
-
"@deepseek-ai/dsh-client-ui-
|
|
83
|
-
"@deepseek-ai/dsh-
|
|
84
|
-
"@deepseek-ai/dsh-
|
|
85
|
-
"@deepseek-ai/dsh-
|
|
86
|
-
"@deepseek-ai/dsh-
|
|
87
|
-
"@deepseek-ai/dsh-
|
|
88
|
-
"@deepseek-ai/dsh-
|
|
89
|
-
"@deepseek-ai/dsh-
|
|
90
|
-
"@deepseek-ai/dsh-
|
|
91
|
-
"@deepseek-ai/dsh-
|
|
76
|
+
"@deepseek-ai/cordis-plugin-loader": "~1.0.5",
|
|
77
|
+
"@deepseek-ai/dsh-agent": ">=0.2.0-rc.2 <0.2.1",
|
|
78
|
+
"@deepseek-ai/dsh-attachment": ">=0.2.0-rc.2 <0.2.1",
|
|
79
|
+
"@deepseek-ai/dsh-client-locale": ">=0.2.0-rc.2 <0.2.1",
|
|
80
|
+
"@deepseek-ai/dsh-client-modules": ">=0.2.0-rc.2 <0.2.1",
|
|
81
|
+
"@deepseek-ai/dsh-client-store": ">=0.2.0-rc.2 <0.2.1",
|
|
82
|
+
"@deepseek-ai/dsh-client-ui-chat": ">=0.2.0-rc.2 <0.2.1",
|
|
83
|
+
"@deepseek-ai/dsh-client-ui-conversation": ">=0.2.0-rc.2 <0.2.1",
|
|
84
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager": ">=0.2.0-rc.2 <0.2.1",
|
|
85
|
+
"@deepseek-ai/dsh-client-ui-settings": ">=0.2.0-rc.2 <0.2.1",
|
|
86
|
+
"@deepseek-ai/dsh-compaction": ">=0.2.0-rc.2 <0.2.1",
|
|
87
|
+
"@deepseek-ai/dsh-credentials": ">=0.2.0-rc.2 <0.2.1",
|
|
88
|
+
"@deepseek-ai/dsh-fs": ">=0.2.0-rc.2 <0.2.1",
|
|
89
|
+
"@deepseek-ai/dsh-llm": ">=0.2.0-rc.2 <0.2.1",
|
|
90
|
+
"@deepseek-ai/dsh-session": ">=0.2.0-rc.2 <0.2.1",
|
|
91
|
+
"@deepseek-ai/dsh-session-query": ">=0.2.0-rc.2 <0.2.1",
|
|
92
|
+
"@deepseek-ai/dsh-settings": ">=0.2.0-rc.2 <0.2.1",
|
|
93
|
+
"@deepseek-ai/dsh-tool-web": ">=0.2.0-rc.2 <0.2.1",
|
|
94
|
+
"@deepseek-ai/dsh-tools": ">=0.2.0-rc.2 <0.2.1",
|
|
95
|
+
"@deepseek-ai/dsh-web": ">=0.2.0-rc.2 <0.2.1",
|
|
92
96
|
"@deepseek-ai/schemastery": "^3.18.2",
|
|
93
97
|
"react": "^18.2.0",
|
|
94
|
-
"@deepseek-ai/dsh-token-meter": ">=0.
|
|
95
|
-
"@deepseek-ai/dsh-session-projection": ">=0.
|
|
98
|
+
"@deepseek-ai/dsh-token-meter": ">=0.2.0-rc.2 <0.2.1",
|
|
99
|
+
"@deepseek-ai/dsh-session-projection": ">=0.2.0-rc.2 <0.2.1",
|
|
96
100
|
"zod": "^4.5.4"
|
|
97
101
|
},
|
|
98
102
|
"peerDependenciesMeta": {
|
|
103
|
+
"@deepseek-ai/cordis-plugin-loader": {
|
|
104
|
+
"optional": true
|
|
105
|
+
},
|
|
99
106
|
"@deepseek-ai/dsh-client-locale": {
|
|
100
107
|
"optional": true
|
|
101
108
|
},
|
|
@@ -117,7 +124,10 @@
|
|
|
117
124
|
"@deepseek-ai/dsh-client-ui-conversation": {
|
|
118
125
|
"optional": true
|
|
119
126
|
},
|
|
120
|
-
"@deepseek-ai/dsh-client-ui-
|
|
127
|
+
"@deepseek-ai/dsh-client-ui-plugin-manager": {
|
|
128
|
+
"optional": true
|
|
129
|
+
},
|
|
130
|
+
"@deepseek-ai/dsh-client-ui-settings": {
|
|
121
131
|
"optional": true
|
|
122
132
|
},
|
|
123
133
|
"@deepseek-ai/dsh-compaction": {
|
|
@@ -135,6 +145,9 @@
|
|
|
135
145
|
"@deepseek-ai/dsh-session": {
|
|
136
146
|
"optional": true
|
|
137
147
|
},
|
|
148
|
+
"@deepseek-ai/dsh-session-query": {
|
|
149
|
+
"optional": true
|
|
150
|
+
},
|
|
138
151
|
"@deepseek-ai/dsh-settings": {
|
|
139
152
|
"optional": true
|
|
140
153
|
},
|
|
@@ -166,8 +179,9 @@
|
|
|
166
179
|
},
|
|
167
180
|
"license": "MIT",
|
|
168
181
|
"lcxCompatibility": {
|
|
169
|
-
"dshInstallRange": ">=0.
|
|
170
|
-
"verifiedDsh": "0.
|
|
171
|
-
"verifiedHostPi": "0.
|
|
182
|
+
"dshInstallRange": ">=0.2.0-rc.2 <0.2.1",
|
|
183
|
+
"verifiedDsh": "0.2.0-rc.2",
|
|
184
|
+
"verifiedHostPi": "0.87.1",
|
|
185
|
+
"verifiedPluginPi": "0.87.1"
|
|
172
186
|
}
|
|
173
187
|
}
|