dsh-ios-webview-app-control 0.0.0-stage → 0.2.2

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 (57) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/LICENSE +21 -0
  3. package/README.md +250 -2
  4. package/THIRD_PARTY_NOTICES.md +42 -0
  5. package/cordis.patch.yml +20 -0
  6. package/docs/installation.md +68 -0
  7. package/docs/new-session-prompt.md +29 -0
  8. package/docs/runtime-environment.md +40 -0
  9. package/docs/sdk-contract.md +79 -0
  10. package/docs/verification.md +64 -0
  11. package/icon.svg +8 -0
  12. package/lib/cli.mjs +51 -0
  13. package/lib/client.js +223 -0
  14. package/lib/core/dom.mjs +26 -0
  15. package/lib/core/leases.mjs +31 -0
  16. package/lib/core/protocol.mjs +101 -0
  17. package/lib/core/python.mjs +47 -0
  18. package/lib/core/service.mjs +122 -0
  19. package/lib/host/environment-service.mjs +175 -0
  20. package/lib/host/subprocess-runner.mjs +34 -0
  21. package/lib/plugin.mjs +303 -0
  22. package/lib/runtime/environment-manager.mjs +544 -0
  23. package/lib/runtime/errors.mjs +33 -0
  24. package/lib/runtime/runner.mjs +75 -0
  25. package/lib/runtime/safe-tar.mjs +179 -0
  26. package/lib/typert-environment.mjs +103 -0
  27. package/locale/en.json +6 -0
  28. package/locale/zh.json +6 -0
  29. package/package.json +72 -4
  30. package/requirements.txt +1 -0
  31. package/resources/notices/PBS-LICENSE.bdb.txt +126 -0
  32. package/resources/notices/PBS-LICENSE.bzip2.txt +37 -0
  33. package/resources/notices/PBS-LICENSE.cpython.txt +771 -0
  34. package/resources/notices/PBS-LICENSE.expat.txt +21 -0
  35. package/resources/notices/PBS-LICENSE.libX11.txt +942 -0
  36. package/resources/notices/PBS-LICENSE.libXau.txt +21 -0
  37. package/resources/notices/PBS-LICENSE.libedit.txt +29 -0
  38. package/resources/notices/PBS-LICENSE.libffi.txt +21 -0
  39. package/resources/notices/PBS-LICENSE.liblzma.txt +13 -0
  40. package/resources/notices/PBS-LICENSE.libuuid.txt +27 -0
  41. package/resources/notices/PBS-LICENSE.libxcb.txt +30 -0
  42. package/resources/notices/PBS-LICENSE.mpdecimal.txt +24 -0
  43. package/resources/notices/PBS-LICENSE.ncurses.txt +29 -0
  44. package/resources/notices/PBS-LICENSE.openssl-3.txt +177 -0
  45. package/resources/notices/PBS-LICENSE.sqlite.txt +23 -0
  46. package/resources/notices/PBS-LICENSE.tcl.txt +40 -0
  47. package/resources/notices/PBS-LICENSE.tix.txt +54 -0
  48. package/resources/notices/PBS-LICENSE.zlib-ng.txt +19 -0
  49. package/resources/notices/PBS-LICENSE.zlib.txt +21 -0
  50. package/resources/notices/PBS-LICENSE.zstd.txt +30 -0
  51. package/resources/notices/PYMOBILEDEVICE3-LICENSE.txt +674 -0
  52. package/resources/notices/PYTHON-LICENSE.txt +277 -0
  53. package/resources/notices/provenance.json +134 -0
  54. package/resources/runtime-lock.json +4252 -0
  55. package/scripts/manage-desktop.ps1 +56 -0
  56. package/scripts/package-validation.mjs +223 -0
  57. package/scripts/verify-package.mjs +13 -0
@@ -0,0 +1,75 @@
1
+ import { spawn } from 'node:child_process';
2
+ import path from 'node:path';
3
+ import { EnvironmentError, aborted, bounded } from './errors.mjs';
4
+
5
+ const OUTPUT_LIMIT = 1024 * 1024;
6
+
7
+ /** Default non-DSH runner. Inject the Host managed runner when a process-range service is available. */
8
+ export async function defaultRunner(executable, args = [], { signal, timeoutMs = 15000, env, cwd, onOutput } = {}) {
9
+ aborted(signal);
10
+ return new Promise((resolve, reject) => {
11
+ const child = spawn(executable, args, {
12
+ shell: false, windowsHide: true, cwd, env,
13
+ detached: process.platform !== 'win32',
14
+ stdio: ['ignore', 'pipe', 'pipe'],
15
+ });
16
+ let stdout = '';
17
+ let stderr = '';
18
+ let failure = null;
19
+ let terminating = null;
20
+ let escalation = null;
21
+ const terminate = () => {
22
+ if (terminating) return terminating;
23
+ if (!child.pid) return Promise.resolve();
24
+ if (process.platform === 'win32') {
25
+ const systemRoot = process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows';
26
+ const taskkill = path.win32.join(systemRoot, 'System32', 'taskkill.exe');
27
+ terminating = new Promise(done => {
28
+ let killer;
29
+ try {
30
+ killer = spawn(taskkill, ['/PID', String(child.pid), '/T', '/F'], { shell: false, windowsHide: true, stdio: 'ignore' });
31
+ } catch { try { child.kill(); } catch {} done(); return; }
32
+ killer.once('error', () => { try { child.kill(); } catch {} });
33
+ killer.once('close', done);
34
+ });
35
+ } else {
36
+ try { process.kill(-child.pid, 'SIGTERM'); } catch {}
37
+ escalation = setTimeout(() => { try { process.kill(-child.pid, 'SIGKILL'); } catch {} }, 1000);
38
+ terminating = Promise.resolve();
39
+ }
40
+ return terminating;
41
+ };
42
+ const abort = () => {
43
+ failure ||= new EnvironmentError(signal?.reason?.code === 'runtime_timeout' ? 'runtime_timeout' : 'cancelled', 'Runtime subprocess was cancelled.');
44
+ void terminate();
45
+ };
46
+ const timer = setTimeout(() => {
47
+ failure ||= new EnvironmentError('runtime_process_timeout', 'Runtime subprocess exceeded its deadline.');
48
+ void terminate();
49
+ }, timeoutMs);
50
+ const output = (stream, chunk) => {
51
+ const text = chunk.toString('utf8');
52
+ const current = stream === 'stdout' ? stdout : stderr;
53
+ if (Buffer.byteLength(current) + chunk.length > OUTPUT_LIMIT) {
54
+ failure ||= new EnvironmentError('runtime_output_limit', 'Runtime subprocess output exceeded 1 MiB.');
55
+ void terminate();
56
+ return;
57
+ }
58
+ if (stream === 'stdout') stdout += text; else stderr += text;
59
+ try { onOutput?.(stream, bounded(text, 4096)); } catch {}
60
+ };
61
+ signal?.addEventListener('abort', abort, { once: true });
62
+ child.stdout.on('data', chunk => output('stdout', chunk));
63
+ child.stderr.on('data', chunk => output('stderr', chunk));
64
+ child.once('error', error => { failure ||= new EnvironmentError('runtime_process_error', bounded(error.message)); });
65
+ child.once('close', async code => {
66
+ clearTimeout(timer);
67
+ if (escalation) clearTimeout(escalation);
68
+ signal?.removeEventListener('abort', abort);
69
+ await terminating;
70
+ if (failure) reject(failure);
71
+ else resolve({ stdout, stderr, exitCode: code ?? 1 });
72
+ });
73
+ if (signal?.aborted) abort();
74
+ });
75
+ }
@@ -0,0 +1,179 @@
1
+ import { createGunzip } from 'node:zlib';
2
+ import { Readable } from 'node:stream';
3
+ import { lstat, mkdir, writeFile } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { EnvironmentError, aborted } from './errors.mjs';
6
+
7
+ const BLOCK = 512;
8
+ const MAX_ENTRIES = 100_000;
9
+ const MAX_EXPANDED = 512 * 1024 * 1024;
10
+ const MAX_ENTRY = 256 * 1024 * 1024;
11
+ const MAX_METADATA = 1024 * 1024;
12
+
13
+ function reject(message) {
14
+ throw new EnvironmentError('runtime_archive_invalid', message);
15
+ }
16
+
17
+ function string(header, start, length) {
18
+ const bytes = header.subarray(start, start + length);
19
+ const zero = bytes.indexOf(0);
20
+ return bytes.subarray(0, zero < 0 ? bytes.length : zero).toString('utf8');
21
+ }
22
+
23
+ function number(header, start, length) {
24
+ const raw = header.subarray(start, start + length);
25
+ if (raw[0] & 0x80) reject('Tar base-256 sizes are not supported.');
26
+ const text = string(header, start, length).trim();
27
+ if (text && !/^[0-7]+$/.test(text)) reject('Tar contains an invalid numeric field.');
28
+ const result = text ? parseInt(text, 8) : 0;
29
+ if (!Number.isSafeInteger(result)) reject('Tar numeric field exceeds the safe bound.');
30
+ return result;
31
+ }
32
+
33
+ function safeName(value) {
34
+ if (!value || value.length > 1024 || /[\\\x00-\x1f:\x7f]/.test(value) || value.startsWith('/')) reject('Tar contains an absolute, ADS, control-character or unsafe path.');
35
+ const name = value.replace(/\/+$/, '');
36
+ const parts = name.split('/');
37
+ if (parts.some(part => !part || part === '.' || part === '..' || /[. ]$/.test(part) || /^(?:CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])(?:\.|$)/i.test(part))) reject('Tar contains a traversal or reserved Windows path.');
38
+ return parts.join('/');
39
+ }
40
+
41
+ function pax(bytes) {
42
+ const output = {};
43
+ let offset = 0;
44
+ while (offset < bytes.length) {
45
+ const space = bytes.indexOf(32, offset);
46
+ if (space < 0) reject('Tar contains malformed PAX metadata.');
47
+ const lengthText = bytes.toString('ascii', offset, space);
48
+ if (!/^[0-9]+$/.test(lengthText)) reject('Tar contains malformed PAX record lengths.');
49
+ const length = Number(lengthText);
50
+ if (!Number.isSafeInteger(length) || length <= space - offset + 1 || offset + length > bytes.length || bytes[offset + length - 1] !== 10) reject('Tar contains truncated PAX metadata.');
51
+ const text = bytes.toString('utf8', space + 1, offset + length - 1);
52
+ const equals = text.indexOf('=');
53
+ if (equals < 1) reject('Tar contains malformed PAX metadata.');
54
+ const key = text.slice(0, equals);
55
+ if (/linkpath|sparse/i.test(key)) reject('Tar PAX links and sparse files are forbidden.');
56
+ output[key] = text.slice(equals + 1);
57
+ offset += length;
58
+ }
59
+ return output;
60
+ }
61
+
62
+ async function ensureDirectory(root, relative) {
63
+ let current = root;
64
+ for (const part of relative ? relative.split('/') : []) {
65
+ current = path.join(current, part);
66
+ try {
67
+ const entry = await lstat(current);
68
+ if (!entry.isDirectory() || entry.isSymbolicLink()) reject('Tar parent path is not a private real directory.');
69
+ } catch (error) {
70
+ if (error?.code !== 'ENOENT') throw error;
71
+ await mkdir(current, { mode: 0o700 });
72
+ }
73
+ }
74
+ }
75
+
76
+ /** Bounded tar.gz extraction. No symlinks, hardlinks, devices, sparse files or writes outside destination. */
77
+ export async function extractSafeTarGz(archive, destination, { signal, maxExpanded = MAX_EXPANDED, maxEntries = MAX_ENTRIES } = {}) {
78
+ aborted(signal);
79
+ await mkdir(destination, { recursive: true, mode: 0o700 });
80
+ if ((await lstat(destination)).isSymbolicLink()) reject('Archive destination must not be a symlink.');
81
+ const gunzip = createGunzip();
82
+ const source = Readable.from(archive);
83
+ const input = source.pipe(gunzip);
84
+ const iterator = input[Symbol.asyncIterator]();
85
+ let buffer = Buffer.alloc(0);
86
+ let expanded = 0;
87
+ let done = false;
88
+ const stop = () => { source.destroy(); input.destroy(new EnvironmentError('cancelled', 'Runtime extraction was cancelled.')); };
89
+ signal?.addEventListener('abort', stop, { once: true });
90
+ const take = async length => {
91
+ while (buffer.length < length && !done) {
92
+ aborted(signal);
93
+ const next = await iterator.next();
94
+ done = next.done === true;
95
+ if (!done) {
96
+ expanded += next.value.length;
97
+ if (expanded > maxExpanded) reject('Archive expands beyond the allowed size.');
98
+ buffer = Buffer.concat([buffer, next.value]);
99
+ }
100
+ }
101
+ if (buffer.length < length) reject('Tar contains a truncated record.');
102
+ const value = buffer.subarray(0, length);
103
+ buffer = buffer.subarray(length);
104
+ return value;
105
+ };
106
+ const names = new Set();
107
+ let entries = 0;
108
+ let globalPax = {};
109
+ let localPax = {};
110
+ let longName = null;
111
+ try {
112
+ for (;;) {
113
+ const header = await take(BLOCK);
114
+ if (header.every(byte => byte === 0)) {
115
+ const second = await take(BLOCK);
116
+ if (!second.every(byte => byte === 0)) reject('Tar end-of-archive marker is invalid.');
117
+ while (!done) {
118
+ const next = await iterator.next();
119
+ done = next.done === true;
120
+ if (!done) {
121
+ expanded += next.value.length;
122
+ if (expanded > maxExpanded || next.value.some(byte => byte !== 0)) reject('Archive has excessive or nonzero trailing data.');
123
+ }
124
+ }
125
+ if (buffer.some(byte => byte !== 0)) reject('Archive has nonzero trailing data.');
126
+ break;
127
+ }
128
+ entries++;
129
+ if (entries > maxEntries) reject('Archive contains too many entries.');
130
+ const expectedChecksum = number(header, 148, 8);
131
+ let actualChecksum = 0;
132
+ for (let index = 0; index < BLOCK; index++) actualChecksum += index >= 148 && index < 156 ? 32 : header[index];
133
+ if (expectedChecksum !== actualChecksum) reject('Tar header checksum is invalid.');
134
+ const type = String.fromCharCode(header[156] || 48);
135
+ let size = number(header, 124, 12);
136
+ const metadata = { ...globalPax, ...localPax };
137
+ if (metadata.size !== undefined) {
138
+ if (!/^[0-9]+$/.test(metadata.size)) reject('PAX size is invalid.');
139
+ size = Number(metadata.size);
140
+ }
141
+ if (!Number.isSafeInteger(size) || size < 0 || size > MAX_ENTRY || size > maxExpanded) reject('Archive entry exceeds the allowed size.');
142
+ if (['x', 'g', 'L'].includes(type)) {
143
+ if (size > MAX_METADATA) reject('Tar metadata exceeds its bound.');
144
+ const data = await take(Math.ceil(size / BLOCK) * BLOCK);
145
+ if (type === 'L') longName = data.subarray(0, size).toString('utf8').replace(/\0.*$/s, '');
146
+ else if (type === 'g') globalPax = { ...globalPax, ...pax(data.subarray(0, size)) };
147
+ else localPax = pax(data.subarray(0, size));
148
+ continue;
149
+ }
150
+ if (type !== '0' && type !== '5') reject('Archive links and special file types are forbidden.');
151
+ const prefix = string(header, 345, 155);
152
+ const name = safeName(metadata.path || longName || [prefix, string(header, 0, 100)].filter(Boolean).join('/'));
153
+ localPax = {};
154
+ longName = null;
155
+ const canonical = name.toLowerCase();
156
+ if (names.has(canonical)) reject('Archive contains duplicate or case-colliding paths.');
157
+ names.add(canonical);
158
+ const target = path.resolve(destination, ...name.split('/'));
159
+ const relative = path.relative(destination, target);
160
+ if (relative.startsWith('..') || path.isAbsolute(relative)) reject('Archive path escapes its private directory.');
161
+ if (type === '5') {
162
+ if (size !== 0) reject('Tar directory has nonzero content.');
163
+ await ensureDirectory(destination, name);
164
+ } else {
165
+ await ensureDirectory(destination, name.includes('/') ? name.slice(0, name.lastIndexOf('/')) : '');
166
+ const data = await take(Math.ceil(size / BLOCK) * BLOCK);
167
+ await writeFile(target, data.subarray(0, size), { flag: 'wx', mode: 0o600 });
168
+ }
169
+ }
170
+ return { entries, expandedBytes: expanded };
171
+ } catch (error) {
172
+ if (error instanceof EnvironmentError) throw error;
173
+ throw new EnvironmentError('runtime_archive_invalid', `Cannot extract locked tar.gz: ${error?.message || error}`);
174
+ } finally {
175
+ signal?.removeEventListener('abort', stop);
176
+ source.destroy();
177
+ input.destroy();
178
+ }
179
+ }
@@ -0,0 +1,103 @@
1
+ import { z } from 'zod';
2
+
3
+ // Hand-authored against DSH rc.5 InvocationDescriptor / TypertContribution.
4
+ // The Client embeds this package's own descriptor, never a Harness UI module.
5
+ export const IOS_ENVIRONMENT_PACKAGE = 'dsh-ios-webview-app-control';
6
+ export const IOS_ENVIRONMENT_SERVICE = 'iosEnvironment';
7
+ export const ENVIRONMENT_PHASES = Object.freeze([
8
+ 'unprepared', 'checking', 'downloading', 'creating', 'installing', 'verifying',
9
+ 'ready', 'failed', 'cancelled',
10
+ ]);
11
+
12
+ export const EnvironmentSnapshotSchema = z.strictObject({
13
+ phase: z.enum(ENVIRONMENT_PHASES),
14
+ busy: z.boolean(),
15
+ step: z.string().max(256),
16
+ progress: z.strictObject({
17
+ completedBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
18
+ totalBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).optional(),
19
+ }).nullable().optional(),
20
+ python: z.strictObject({
21
+ path: z.string().max(8192),
22
+ version: z.string().max(128),
23
+ source: z.enum(['host', 'private']),
24
+ abi: z.string().max(128).optional(),
25
+ }).nullable().optional(),
26
+ runtimeDir: z.string().max(8192).optional(),
27
+ pymobiledevice3: z.string().max(128).optional(),
28
+ error: z.strictObject({
29
+ code: z.string().max(128),
30
+ message: z.string().max(2048),
31
+ }).nullable().optional(),
32
+ });
33
+
34
+ /** Only named public environment fields cross the Remote boundary. */
35
+ export function projectEnvironmentSnapshot(raw) {
36
+ const snapshot = { phase: raw?.phase, busy: raw?.busy, step: raw?.step ?? raw?.phase };
37
+ if (raw?.progress === null) snapshot.progress = null;
38
+ else if (raw?.progress !== undefined) {
39
+ snapshot.progress = { completedBytes: raw.progress.completedBytes };
40
+ if (raw.progress.totalBytes !== undefined) snapshot.progress.totalBytes = raw.progress.totalBytes;
41
+ }
42
+ if (raw?.python === null) snapshot.python = null;
43
+ else if (raw?.python !== undefined) {
44
+ snapshot.python = { path: raw.python.path, version: raw.python.version, source: raw.python.source };
45
+ if (raw.python.abi !== undefined) snapshot.python.abi = raw.python.abi;
46
+ }
47
+ for (const key of ['runtimeDir', 'pymobiledevice3']) {
48
+ if (raw?.[key] !== undefined) snapshot[key] = raw[key];
49
+ }
50
+ if (raw?.error === null) snapshot.error = null;
51
+ else if (raw?.error !== undefined) snapshot.error = { code: raw.error.code, message: raw.error.message };
52
+ return EnvironmentSnapshotSchema.parse(snapshot);
53
+ }
54
+
55
+ export const environmentSnapshotCodec = Object.freeze({
56
+ mode: 'strict',
57
+ typeSymbol: `${IOS_ENVIRONMENT_PACKAGE}#EnvironmentSnapshot`,
58
+ create: () => EnvironmentSnapshotSchema,
59
+ // Gateway does not parse Host results itself; enforce the output boundary too.
60
+ encode: value => EnvironmentSnapshotSchema.parse(value),
61
+ decode: value => EnvironmentSnapshotSchema.parse(value),
62
+ });
63
+
64
+ export const environmentInvocations = Object.freeze(
65
+ ['status', 'prepare', 'cancel', 'cleanup', 'follow'].map(method => Object.freeze({
66
+ id: `${IOS_ENVIRONMENT_PACKAGE}#${IOS_ENVIRONMENT_SERVICE}/${method}`,
67
+ service: IOS_ENVIRONMENT_SERVICE,
68
+ namespace: IOS_ENVIRONMENT_SERVICE,
69
+ method,
70
+ invocation: Object.freeze({ kind: 'direct' }),
71
+ parameters: Object.freeze([]),
72
+ cancellation: Object.freeze({ parameter: 'signal' }),
73
+ ...(method === 'follow' ? { mode: 'stream' } : {}),
74
+ result: environmentSnapshotCodec,
75
+ })),
76
+ );
77
+
78
+ export const environmentHostContribution = Object.freeze({
79
+ package: IOS_ENVIRONMENT_PACKAGE,
80
+ face: 'host',
81
+ schemas: Object.freeze([{ name: 'EnvironmentSnapshot', create: () => EnvironmentSnapshotSchema }]),
82
+ model: Object.freeze({
83
+ services: [{
84
+ key: IOS_ENVIRONMENT_SERVICE,
85
+ exportName: 'IosEnvironmentService',
86
+ description: 'Host-owned Python environment preparation; never contacts a phone.',
87
+ tags: [],
88
+ members: environmentInvocations.map(({ method }) => ({
89
+ kind: 'method', name: method,
90
+ signature: method === 'follow'
91
+ ? 'follow(signal: AbortSignal): AsyncIterable<EnvironmentSnapshot>'
92
+ : `${method}(signal: AbortSignal): Promise<EnvironmentSnapshot>`,
93
+ })),
94
+ types: [{
95
+ name: 'EnvironmentSnapshot',
96
+ declaration: 'export interface EnvironmentSnapshot { readonly phase: "unprepared" | "checking" | "downloading" | "creating" | "installing" | "verifying" | "ready" | "failed" | "cancelled"; readonly busy: boolean; readonly step: string; readonly progress?: { readonly completedBytes: number; readonly totalBytes?: number } | null; readonly python?: { readonly path: string; readonly version: string; readonly source: "host" | "private"; readonly abi?: string } | null; readonly runtimeDir?: string; readonly pymobiledevice3?: string; readonly error?: { readonly code: string; readonly message: string } | null; }',
97
+ }],
98
+ }],
99
+ objects: [],
100
+ events: [],
101
+ }),
102
+ invocations: environmentInvocations,
103
+ });
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "iOS WebView App Control",
4
+ "description": "This plugin controls confirmed iOS WebView/hybrid targets through an existing local bridge, with per-operation approval and session-owned leases. Its limits do not describe other DSH tools."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "iOS WebView 应用控制",
4
+ "description": "本插件通过已有本机桥接控制已确认的 iOS WebView/混合应用,逐次审批并使用会话专属设备租约。其能力限制不代表 DSH 会话中其它工具的能力。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,74 @@
1
1
  {
2
2
  "name": "dsh-ios-webview-app-control",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.2",
4
+ "description": "Business-free DSH tools for inspectable iOS WebView/hybrid apps only.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "engines": {
8
+ "node": ">=22.18.0",
9
+ "dsh": ">=0.2.1-rc.5 <0.3.0"
10
+ },
11
+ "main": "./lib/plugin.mjs",
12
+ "exports": {
13
+ ".": "./lib/plugin.mjs",
14
+ "./core": "./lib/core/service.mjs",
15
+ "./client": "./lib/client.js",
16
+ "./cordis.patch.yml": "./cordis.patch.yml",
17
+ "./locale/*.json": "./locale/*.json",
18
+ "./icon": "./icon.svg",
19
+ "./package.json": "./package.json"
20
+ },
21
+ "bin": {
22
+ "dsh-ios-webview-app-control": "./lib/cli.mjs"
23
+ },
24
+ "files": [
25
+ "lib/",
26
+ "resources/",
27
+ "THIRD_PARTY_NOTICES.md",
28
+ "cordis.patch.yml",
29
+ "README.md",
30
+ "docs/",
31
+ "requirements.txt",
32
+ "LICENSE",
33
+ "CHANGELOG.md",
34
+ "locale/*.json",
35
+ "icon.svg",
36
+ "scripts/manage-desktop.ps1",
37
+ "scripts/verify-package.mjs",
38
+ "scripts/package-validation.mjs"
39
+ ],
40
+ "dsh": {
41
+ "bundle": {
42
+ "patch": "./cordis.patch.yml"
43
+ },
44
+ "client": {
45
+ "platform": "web",
46
+ "immediately": true,
47
+ "external": ["zod"],
48
+ "inject": ["@deepseek-ai/dsh-client-ui-plugin-manager", "@deepseek-ai/dsh-client-ui-settings-plugins"]
49
+ }
50
+ },
51
+ "scripts": {
52
+ "build": "node scripts/build.mjs",
53
+ "test": "node --test test/*.test.mjs",
54
+ "check": "node scripts/check.mjs",
55
+ "prepack": "npm run build && npm run check && npm test"
56
+ },
57
+ "dependencies": {
58
+ "@deepseek-ai/schemastery": "~3.18.5",
59
+ "zod": "4.4.3"
60
+ },
61
+ "devDependencies": {
62
+ "@deepseek-ai/dsh-api-gateway": "0.2.1-rc.5",
63
+ "@deepseek-ai/dsh-api-remote-access": "0.2.1-rc.5",
64
+ "@deepseek-ai/dsh-typert-registry": "0.2.1-rc.5"
65
+ },
66
+ "peerDependencies": {
67
+ "@deepseek-ai/cordis": "~4.0.5",
68
+ "@deepseek-ai/dsh-tools": "^0.2.1-rc.5",
69
+ "@deepseek-ai/dsh-system-prompt": "^0.2.1-rc.5",
70
+ "@deepseek-ai/dsh-user-approval": "^0.2.1-rc.5",
71
+ "@deepseek-ai/dsh-llm": "^0.2.1-rc.5",
72
+ "@deepseek-ai/dsh-typert-protocol": "^0.2.1-rc.5"
73
+ }
74
+ }
@@ -0,0 +1 @@
1
+ pymobiledevice3==11.45.0
@@ -0,0 +1,126 @@
1
+ The following is the license that applies to this copy of the Berkeley DB
2
+ software. For a license to use the Berkeley DB software under conditions
3
+ other than those described here, or to purchase support for this software,
4
+ please contact Oracle at berkeleydb-info_us@oracle.com.
5
+
6
+ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7
+ /*
8
+ * Copyright (c) 1990, 2013 Oracle and/or its affiliates. All rights reserved.
9
+ *
10
+ * Redistribution and use in source and binary forms, with or without
11
+ * modification, are permitted provided that the following conditions
12
+ * are met:
13
+ * 1. Redistributions of source code must retain the above copyright
14
+ * notice, this list of conditions and the following disclaimer.
15
+ * 2. Redistributions in binary form must reproduce the above copyright
16
+ * notice, this list of conditions and the following disclaimer in the
17
+ * documentation and/or other materials provided with the distribution.
18
+ * 3. Redistributions in any form must be accompanied by information on
19
+ * how to obtain complete source code for the DB software and any
20
+ * accompanying software that uses the DB software. The source code
21
+ * must either be included in the distribution or be available for no
22
+ * more than the cost of distribution plus a nominal fee, and must be
23
+ * freely redistributable under reasonable conditions. For an
24
+ * executable file, complete source code means the source code for all
25
+ * modules it contains. It does not include source code for modules or
26
+ * files that typically accompany the major components of the operating
27
+ * system on which the executable file runs.
28
+ *
29
+ * THIS SOFTWARE IS PROVIDED BY ORACLE ``AS IS'' AND ANY EXPRESS OR
30
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31
+ * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
32
+ * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL ORACLE BE LIABLE
33
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
36
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
37
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
38
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
39
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
+ */
41
+ /*
42
+ * Copyright (c) 1990, 1993, 1994, 1995
43
+ * The Regents of the University of California. All rights reserved.
44
+ *
45
+ * Redistribution and use in source and binary forms, with or without
46
+ * modification, are permitted provided that the following conditions
47
+ * are met:
48
+ * 1. Redistributions of source code must retain the above copyright
49
+ * notice, this list of conditions and the following disclaimer.
50
+ * 2. Redistributions in binary form must reproduce the above copyright
51
+ * notice, this list of conditions and the following disclaimer in the
52
+ * documentation and/or other materials provided with the distribution.
53
+ * 3. Neither the name of the University nor the names of its contributors
54
+ * may be used to endorse or promote products derived from this software
55
+ * without specific prior written permission.
56
+ *
57
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67
+ * SUCH DAMAGE.
68
+ */
69
+ /*
70
+ * Copyright (c) 1995, 1996
71
+ * The President and Fellows of Harvard University. All rights reserved.
72
+ *
73
+ * Redistribution and use in source and binary forms, with or without
74
+ * modification, are permitted provided that the following conditions
75
+ * are met:
76
+ * 1. Redistributions of source code must retain the above copyright
77
+ * notice, this list of conditions and the following disclaimer.
78
+ * 2. Redistributions in binary form must reproduce the above copyright
79
+ * notice, this list of conditions and the following disclaimer in the
80
+ * documentation and/or other materials provided with the distribution.
81
+ * 3. Neither the name of the University nor the names of its contributors
82
+ * may be used to endorse or promote products derived from this software
83
+ * without specific prior written permission.
84
+ *
85
+ * THIS SOFTWARE IS PROVIDED BY HARVARD AND ITS CONTRIBUTORS ``AS IS'' AND
86
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88
+ * ARE DISCLAIMED. IN NO EVENT SHALL HARVARD OR ITS CONTRIBUTORS BE LIABLE
89
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95
+ * SUCH DAMAGE.
96
+ */
97
+ =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
98
+ /***
99
+ * ASM: a very small and fast Java bytecode manipulation framework
100
+ * Copyright (c) 2000-2005 INRIA, France Telecom
101
+ * All rights reserved.
102
+ *
103
+ * Redistribution and use in source and binary forms, with or without
104
+ * modification, are permitted provided that the following conditions
105
+ * are met:
106
+ * 1. Redistributions of source code must retain the above copyright
107
+ * notice, this list of conditions and the following disclaimer.
108
+ * 2. Redistributions in binary form must reproduce the above copyright
109
+ * notice, this list of conditions and the following disclaimer in the
110
+ * documentation and/or other materials provided with the distribution.
111
+ * 3. Neither the name of the copyright holders nor the names of its
112
+ * contributors may be used to endorse or promote products derived from
113
+ * this software without specific prior written permission.
114
+ *
115
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
116
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
117
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
118
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
119
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
120
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
121
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
122
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
123
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
124
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
125
+ * THE POSSIBILITY OF SUCH DAMAGE.
126
+ */
@@ -0,0 +1,37 @@
1
+ This program, "bzip2", the associated library "libbzip2", and all
2
+ documentation, are copyright (C) 1996-2010 Julian R Seward. All
3
+ rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions
7
+ are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright
10
+ notice, this list of conditions and the following disclaimer.
11
+
12
+ 2. The origin of this software must not be misrepresented; you must
13
+ not claim that you wrote the original software. If you use this
14
+ software in a product, an acknowledgment in the product
15
+ documentation would be appreciated but is not required.
16
+
17
+ 3. Altered source versions must be plainly marked as such, and must
18
+ not be misrepresented as being the original software.
19
+
20
+ 4. The name of the author may not be used to endorse or promote
21
+ products derived from this software without specific prior written
22
+ permission.
23
+
24
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
25
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
28
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
30
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+
36
+ Julian Seward, jseward@bzip.org
37
+ bzip2/libbzip2 version 1.0.6 of 6 September 2010