pi-background-tasks 0.4.0 → 0.7.0
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/PUBLISHING.md +15 -15
- package/README.md +83 -9
- package/TESTING.md +31 -13
- package/TEST_PLAN.md +19 -9
- package/extensions/background-tasks.ts +1 -1
- package/package.json +16 -10
- package/src/core/attested-pi-run.ts +619 -0
- package/src/core/common.ts +567 -381
- package/src/core/extension-api.ts +548 -0
- package/src/core/fusion/artifacts.ts +443 -0
- package/src/core/fusion/config.ts +371 -0
- package/src/core/fusion/context.ts +179 -0
- package/src/core/fusion/evaluation.ts +362 -0
- package/src/core/fusion/orchestrator.ts +593 -0
- package/src/core/fusion/pi-child.ts +816 -0
- package/src/core/fusion/prompts.ts +155 -0
- package/src/core/fusion/types.ts +288 -0
- package/src/core/registry.ts +1392 -694
- package/src/core/update-check.ts +69 -63
- package/src/extension.ts +863 -524
- package/src/fusion-extension.ts +616 -0
- package/src/testing/normalize.ts +22 -3
- package/src/ui/background-tasks-manager.ts +711 -559
- package/src/ui/fusion-model-selector.ts +322 -0
package/src/core/update-check.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { readFileSync } from
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { isJsonObject, parseJsonText, type JsonObject } from './common.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Typed, offline-safe boundary for the "update available" footer notice.
|
|
@@ -9,91 +10,96 @@ import { readFileSync } from "node:fs";
|
|
|
9
10
|
* footer/session can never hang or error because of an update check.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
|
-
export const DEFAULT_NPM_REGISTRY_URL =
|
|
13
|
+
export const DEFAULT_NPM_REGISTRY_URL = 'https://registry.npmjs.org';
|
|
13
14
|
export const DEFAULT_UPDATE_TIMEOUT_MS = 2000;
|
|
14
15
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
16
|
+
export interface FetchResponseLike {
|
|
17
|
+
readonly ok: boolean;
|
|
18
|
+
readonly status: number;
|
|
19
|
+
json(): Promise<unknown>;
|
|
20
|
+
}
|
|
20
21
|
|
|
21
22
|
export type FetchLike = (url: string, init: { signal: AbortSignal }) => Promise<FetchResponseLike>;
|
|
22
23
|
|
|
23
|
-
export
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
24
|
+
export interface FetchLatestVersionOptions {
|
|
25
|
+
packageName: string;
|
|
26
|
+
registryUrl?: string;
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
fetchImpl?: FetchLike;
|
|
29
|
+
onError?: (error: Error) => void;
|
|
30
|
+
}
|
|
30
31
|
|
|
31
|
-
export
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
32
|
+
export interface PackageInfo {
|
|
33
|
+
name?: string;
|
|
34
|
+
version?: string;
|
|
35
|
+
}
|
|
35
36
|
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
return value as Record<string, unknown>;
|
|
37
|
+
function asPayload(value: unknown): JsonObject | undefined {
|
|
38
|
+
return isJsonObject(value) ? value : undefined;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function readNonEmptyString(record:
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
function readNonEmptyString(record: JsonObject, key: string): string | undefined {
|
|
42
|
+
const value = record[key];
|
|
43
|
+
if (typeof value !== 'string') return undefined;
|
|
44
|
+
const trimmed = value.trim();
|
|
45
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/** Narrow an npm registry `<pkg>/latest` JSON payload to its `version` string. */
|
|
49
49
|
export function parseLatestVersionPayload(payload: unknown): string | undefined {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
const record = asPayload(payload);
|
|
51
|
+
if (!record) return undefined;
|
|
52
|
+
return readNonEmptyString(record, 'version');
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/** Narrow a parsed `package.json` payload to the fields this extension needs. */
|
|
56
56
|
export function parsePackageInfo(payload: unknown): PackageInfo {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
const record = asPayload(payload);
|
|
58
|
+
if (!record) return {};
|
|
59
|
+
const info: PackageInfo = {};
|
|
60
|
+
const name = readNonEmptyString(record, 'name');
|
|
61
|
+
const version = readNonEmptyString(record, 'version');
|
|
62
|
+
if (name !== undefined) info.name = name;
|
|
63
|
+
if (version !== undefined) info.version = version;
|
|
64
|
+
return info;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
const realFetch: FetchLike = (url, init) => fetch(url, init);
|
|
68
68
|
|
|
69
69
|
/** Time-boxed, never-throwing lookup of the latest published version of a package. */
|
|
70
|
-
export async function fetchLatestVersion(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
70
|
+
export async function fetchLatestVersion(
|
|
71
|
+
options: FetchLatestVersionOptions,
|
|
72
|
+
): Promise<string | undefined> {
|
|
73
|
+
const registryUrl = (options.registryUrl ?? DEFAULT_NPM_REGISTRY_URL).replace(/\/+$/, '');
|
|
74
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_UPDATE_TIMEOUT_MS;
|
|
75
|
+
const doFetch = options.fetchImpl ?? realFetch;
|
|
76
|
+
const controller = new AbortController();
|
|
77
|
+
const timer = setTimeout(() => {
|
|
78
|
+
controller.abort();
|
|
79
|
+
}, timeoutMs);
|
|
80
|
+
try {
|
|
81
|
+
const url = `${registryUrl}/${encodeURIComponent(options.packageName)}/latest`;
|
|
82
|
+
const response = await doFetch(url, { signal: controller.signal });
|
|
83
|
+
if (!response.ok) return undefined;
|
|
84
|
+
const payload = await response.json();
|
|
85
|
+
return parseLatestVersionPayload(payload);
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (options.onError) options.onError(error instanceof Error ? error : new Error(String(error)));
|
|
88
|
+
return undefined;
|
|
89
|
+
} finally {
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
}
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
/** Read `name`/`version` from a local `package.json`, returning `{}` on every failure. */
|
|
91
|
-
export function readPackageInfo(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
export function readPackageInfo(
|
|
96
|
+
packageJsonUrl: URL | string,
|
|
97
|
+
onError?: (error: Error) => void,
|
|
98
|
+
): PackageInfo {
|
|
99
|
+
try {
|
|
100
|
+
return parsePackageInfo(parseJsonText(readFileSync(packageJsonUrl, 'utf8')));
|
|
101
|
+
} catch (error) {
|
|
102
|
+
if (onError) onError(error instanceof Error ? error : new Error(String(error)));
|
|
103
|
+
return {};
|
|
104
|
+
}
|
|
99
105
|
}
|