@kaoruisaac/pedelec 0.4.10 → 0.4.12
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 +42 -16
- package/dist/index.d.ts +26 -8
- package/dist/index.js +66 -20
- package/dist/index.type-test.js +22 -1
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/vite.js +3 -3
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -91,9 +91,9 @@ npm install ../path/to/pedelec/sdk
|
|
|
91
91
|
|
|
92
92
|
---
|
|
93
93
|
|
|
94
|
-
##
|
|
94
|
+
## Runtime Modules
|
|
95
95
|
|
|
96
|
-
Vite applications can package local or installed JavaScript/TypeScript libraries for Agent-authored `pedelec-
|
|
96
|
+
Vite applications can package local or installed JavaScript/TypeScript libraries for Agent-authored `pedelec-ts-runtime` scripts.
|
|
97
97
|
|
|
98
98
|
### Setup
|
|
99
99
|
|
|
@@ -110,15 +110,15 @@ export default defineConfig({
|
|
|
110
110
|
### Authoring
|
|
111
111
|
|
|
112
112
|
```ts
|
|
113
|
-
import { Pedelec,
|
|
113
|
+
import { Pedelec, defineRuntimeModule } from "@kaoruisaac/pedelec";
|
|
114
114
|
|
|
115
115
|
const pedelec = new Pedelec();
|
|
116
116
|
const session = await pedelec.createSession({
|
|
117
117
|
skills: {
|
|
118
118
|
guidance: "Use sprite-tools for sprite authoring tasks.",
|
|
119
119
|
tools: [],
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
runtimeModules: [
|
|
121
|
+
defineRuntimeModule({
|
|
122
122
|
name: "sprite-tools",
|
|
123
123
|
description: "Sprite authoring and preview utilities.",
|
|
124
124
|
entry: "./agent/sprite-tools.ts",
|
|
@@ -133,7 +133,7 @@ const session = await pedelec.createSession({
|
|
|
133
133
|
For an installed package, use its package specifier as the build-time entry:
|
|
134
134
|
|
|
135
135
|
```ts
|
|
136
|
-
|
|
136
|
+
defineRuntimeModule({
|
|
137
137
|
name: "gsap",
|
|
138
138
|
description: "Animation utilities.",
|
|
139
139
|
entry: "gsap",
|
|
@@ -145,9 +145,9 @@ defineDenoModule({
|
|
|
145
145
|
|
|
146
146
|
The generated declaration describes the module's Agent-facing API, so implementation-only dependency types are omitted. Module-owned types are supported; packages that expose dependency-owned or Node-specific external types directly in their public API are not guaranteed to produce a standalone declaration in V1. `name` is the Agent import specifier, and `usage` is required common-case guidance. `createSession()` transfers the prepared artifact automatically; a session keeps an immutable module snapshot, and `session.end()`/`session.resume()` reuse it while Core still knows the thread.
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
Runtime Modules are imported inside JavaScript/TypeScript run with `pedelec-ts-runtime`. They are different from `skills.tools`, whose browser/App RPC capabilities use `pedelec-cli` tool-spec and tool-call commands.
|
|
149
149
|
|
|
150
|
-
Set
|
|
150
|
+
Set optional `preferStdinExecution: true` when short scripts primarily use a module. Host Context then exposes `preferredExecution: "stdin"` for that module; the Agent uses the global `runStdinCommand` with `pedelec-ts-runtime`. This is a preference: file-backed execution remains valid. Omitting the field or setting it to `false` preserves default authoring behavior. It does not change bundling, artifacts, or permissions.
|
|
151
151
|
|
|
152
152
|
---
|
|
153
153
|
|
|
@@ -311,7 +311,7 @@ const session = await workspace.createSession({
|
|
|
311
311
|
const workspace = await pedelec.openWorkspace("C:\\workspace\\project-a");
|
|
312
312
|
```
|
|
313
313
|
|
|
314
|
-
Pedelec initializes `.pedelec-runtime` for Workspace-owned runtime data without clearing project files or existing private data. Assets, logs, and temporary data are Workspace-level, while generated Session skills and
|
|
314
|
+
Pedelec initializes `.pedelec-runtime` for Workspace-owned runtime data without clearing project files or existing private data. Assets, logs, and temporary data are Workspace-level, while generated Session skills and Runtime Module state are isolated per Thread. Applications should not depend on the private `.pedelec-runtime` subdirectory layout. Explicit Workspaces are application-managed, are never deleted by Pedelec, and can own multiple Sessions. An explicit path must not overlap Pedelec's managed workspace root.
|
|
315
315
|
|
|
316
316
|
### Managed convenience
|
|
317
317
|
|
|
@@ -339,7 +339,7 @@ const text = await workspace.readFile("README.md", "text");
|
|
|
339
339
|
|
|
340
340
|
`session.uploadAsset()`, `readAsset()`, and `listAssets()` stay available as Session-scoped conveniences. Their root is `.pedelec-runtime/assets`, which suits provider artifacts and Agent-shared assets. Use the Workspace methods for general filesystem access.
|
|
341
341
|
|
|
342
|
-
`workspace.run(script, options?)` executes application-supplied
|
|
342
|
+
`workspace.run(script, options?)` executes application-supplied TypeScript code in the Workspace:
|
|
343
343
|
|
|
344
344
|
```ts
|
|
345
345
|
const result = await workspace.run(
|
|
@@ -355,25 +355,25 @@ const value = JSON.parse(result.stdout);
|
|
|
355
355
|
|
|
356
356
|
The default timeout is 60 seconds; `timeoutMs` must be a positive integer. The return value is the raw `DenoRunOutput` shape: `exitCode`, `stdout`, `stderr`, `stdoutTruncated`, and `stderrTruncated`. A non-zero `exitCode` still resolves normally. The application parses `stdout` when it wants a function-like return value. Check truncation flags before relying on output; an oversized browser response fails with `WORKSPACE_RUN_OUTPUT_TOO_LARGE`.
|
|
357
357
|
|
|
358
|
-
`workspace.run()` has read and write access to the Workspace, but no network, host environment, subprocess execution, FFI, or `sys` permission.
|
|
358
|
+
By default, `workspace.run()` has read and write access to the Workspace, but no network, host environment, subprocess execution, FFI, or `sys` permission. In Sandbox, the existing no-remote, cached-only, and no-npm runtime restrictions still apply. This default mode is a direct capability for an approved Web application and is not mediated by an Agent.
|
|
359
359
|
|
|
360
360
|
Multiple Sessions, Agent/provider operations, and `workspace.run()` executions may operate concurrently in the same Workspace. A second turn on the same Session is still rejected while that Session is busy. Pedelec does not provide filesystem-level locking, snapshots, transactions, or conflict resolution between concurrent Workspace actors. Applications are responsible for coordinating shared file access when required.
|
|
361
361
|
|
|
362
|
-
Session `skills.
|
|
362
|
+
Session `skills.runtimeModules` belong to the Session/Thread that declares them and are available only to Agent-side `pedelec-ts-runtime` execution for that Thread. Workspace runs accept the same Vite-prepared declarations explicitly:
|
|
363
363
|
|
|
364
364
|
```ts
|
|
365
|
-
const sceneTools =
|
|
365
|
+
const sceneTools = defineRuntimeModule({
|
|
366
366
|
name: "scene-tools",
|
|
367
367
|
entry: "./deno/scene-tools.ts",
|
|
368
368
|
});
|
|
369
369
|
|
|
370
370
|
const result = await workspace.run(
|
|
371
371
|
`import { buildScene } from "scene-tools";\nawait buildScene();`,
|
|
372
|
-
{
|
|
372
|
+
{ runtimeModules: [sceneTools] },
|
|
373
373
|
);
|
|
374
374
|
```
|
|
375
375
|
|
|
376
|
-
`workspace.run()` does not inherit any Session
|
|
376
|
+
`workspace.run()` does not inherit any Session Runtime Modules, and Sessions do not inherit modules used by Workspace runs. The Vite-prepared package is cached privately per Workspace and authorized SDK origin; each run receives an import map containing exactly its requested names. A ready module name is immutable for the lifetime of the Core process, and Workspace-run modules never appear in Agent Host Context. The private Workspace-run cache is reset when Core restarts; project files, assets, and Thread module snapshots are preserved.
|
|
377
377
|
|
|
378
378
|
The Workspace handle outlives an individual Session conceptually. Ending a Session does not close or delete a custom Workspace, and Pedelec does not delete it during app cleanup. Managed Workspaces remain under Desktop cleanup ownership and are not promised to disappear immediately when a Thread ends. The browser capability is runtime-scoped; reopen the custom Workspace after a Desktop/Core restart when necessary. `pedelec.resumeSession(sessionId)` returns a Session that already includes `session.workspace`; the application does not need to call `openWorkspace()` separately. Same-handle `session.resume()` preserves the existing Workspace handle, subject to the existing Core/thread and transport caveats.
|
|
379
379
|
|
|
@@ -449,7 +449,7 @@ const modelSession = await pedelec.createSession({
|
|
|
449
449
|
|
|
450
450
|
Model-only requests are valid and use the provider's default effort behavior. `effort` requires `model`; `model` cannot be combined with `effortLevel`. The SDK does not expose or maintain a model catalog, and it does not translate the identifier into provider CLI flags. Model validity, effort support, and account entitlement remain provider-dependent, so an invalid or unavailable configuration may fail when the provider starts.
|
|
451
451
|
|
|
452
|
-
Explicit model requests require an `explicitModelConfigApplied` acknowledgment from Core before the SDK exposes the session or starts
|
|
452
|
+
Explicit model requests require an `explicitModelConfigApplied` acknowledgment from Core before the SDK exposes the session or starts Runtime Module setup. If the connected Extension/Desktop is too old to provide that acknowledgment, the SDK aborts the newly created setup and reports a compatibility error instead of silently using a different configuration.
|
|
453
453
|
|
|
454
454
|
Currently supported provider codes in the SDK:
|
|
455
455
|
|
|
@@ -465,3 +465,29 @@ Currently supported provider codes in the SDK:
|
|
|
465
465
|
Ollama sessions are executed by the bundled `pedelec-agent`. In profile mode, the selected Ollama effort profile must contain a model; otherwise Core returns `MODEL_REQUIRED`. In explicit model mode, `{ model }` supplies the model directly. Ollama currently does not accept an explicit `effort`. Low and high profiles are optional, but there is no fallback between profiles.
|
|
466
466
|
|
|
467
467
|
`getSettings()` returns only `{ defaultProvider }`. It never exposes provider settings, effort arguments, credentials, or model names.
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
## Explicit Full Runtime Access
|
|
471
|
+
|
|
472
|
+
Sandbox is the default. Full Access requires three separate conditions: an Instance created with `runtimeFullAccess: true`, explicit user approval of both **Allow Agent Sessions** and **Allow Full Runtime Access** in the Extension, and `runtimeFullAccess: true` on session creation.
|
|
473
|
+
|
|
474
|
+
The first `createSession()` automatically opens the approval Popup when required grants are missing. Choosing only Agent Sessions leaves a Full Instance incomplete and rejects either Session mode with `CREATE_SESSION_NOT_APPROVED`. `getApprovalStatus()` and `checkAvailability()` only read approval state.
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
const privileged = new Pedelec({ runtimeFullAccess: true });
|
|
478
|
+
// After the user explicitly grants both permissions in the Extension:
|
|
479
|
+
const sandbox = await privileged.createSession({ runtimeFullAccess: false });
|
|
480
|
+
const full = await privileged.createSession({ runtimeFullAccess: true });
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
Review the Extension permissions before creating sessions. An Instance requesting Full Access cannot create any session with only the Agent Sessions grant, including a Sandbox session. A standard Instance cannot request a Full Access session, even if another Instance on the same Origin has permission. Ordinary Origin approval never substitutes for the Full Access grant; the Popup offers an additional permission review with Full Access unchecked by default. `getApprovalStatus()` only reads status and does not open that review.
|
|
484
|
+
|
|
485
|
+
The Thread mode is fixed at creation and preserved on resume. Instances on the same Origin and Threads in the same Workspace retain their own requested modes. `workspace.run()` independently defaults to Sandbox. With a Full Instance and both Extension grants, `workspace.run(script, { runtimeFullAccess: true })` selects Full Access for that run only; no Session is required. Provider sandbox settings are unchanged. Full Access changes the TypeScript Runtime's OS permissions only. Revoking the Full Access grant rejects subsequent high-privilege execution and attempts to cancel affected running processes; unrelated Origins retain their grants.
|
|
486
|
+
|
|
487
|
+
Upgrade the SDK, Extension, and Desktop together when using Full Access. Missing mode acknowledgment is an error, never a successful downgrade. See [Error Codes](https://kaoruisaac.github.io/pedelec/reference/error-codes/) for authorization and protocol failures.
|
|
488
|
+
|
|
489
|
+
## Runtime compatibility
|
|
490
|
+
|
|
491
|
+
New code uses `defineRuntimeModule`, `RuntimeModuleDefinition`, and `runtimeModules`. `defineDenoModule`, `DenoModuleDefinition`, and `denoModules` remain supported deprecated aliases. Never pass both module fields in one options object (`INVALID_INPUT`). `pedelec-ts-runtime --thread-id <id> run scripts/task.ts` and stdin `run -` are the standard CLI; `pedelec-deno` is a legal legacy alias with identical behavior. Actual `Deno.*` APIs, `DENO_DIR`, Deno flags, and `DENO_*` error codes retain their existing meanings.
|
|
492
|
+
|
|
493
|
+
A Full Access Workspace run uses the same host permissions as a Full Access Session, including network, host environment, subprocesses and files outside the Workspace. Revoking Full Runtime Access cancels affected running Full Access executions. A standard Instance cannot request it. Older peers may omit the Sandbox acknowledgment, but a Full Access request fails unless the connected Extension and Desktop confirm the requested mode.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export type PedelecOptions = {
|
|
2
|
+
runtimeFullAccess?: boolean;
|
|
2
3
|
bridgeTimeoutMs?: number;
|
|
3
4
|
};
|
|
4
5
|
export type ProviderCode = "codex" | "antigravity" | "opencode" | "cursor" | "claude" | "ollama";
|
|
@@ -32,14 +33,16 @@ export type ProviderArtifact = {
|
|
|
32
33
|
providerArtifactId?: string;
|
|
33
34
|
toolCallId?: string;
|
|
34
35
|
};
|
|
35
|
-
export type
|
|
36
|
+
export type RuntimeModuleDefinition<TName extends string = string> = {
|
|
36
37
|
name: TName;
|
|
37
38
|
description?: string;
|
|
38
39
|
entry: string;
|
|
39
40
|
usage?: string;
|
|
40
41
|
preferStdinExecution?: boolean;
|
|
41
42
|
};
|
|
42
|
-
|
|
43
|
+
/** @deprecated Use RuntimeModuleDefinition. */
|
|
44
|
+
export type DenoModuleDefinition<TName extends string = string> = RuntimeModuleDefinition<TName>;
|
|
45
|
+
type AgentRuntimeModuleDefinition<TName extends string = string> = RuntimeModuleDefinition<TName> & {
|
|
43
46
|
description: string;
|
|
44
47
|
usage: string;
|
|
45
48
|
};
|
|
@@ -99,7 +102,9 @@ export type ToolDefinition<TArgs = unknown, TResult = unknown, TName extends str
|
|
|
99
102
|
export type SkillsInput<TTools extends readonly ToolDefinition[] = readonly ToolDefinition[]> = {
|
|
100
103
|
guidance: string;
|
|
101
104
|
tools: TTools;
|
|
102
|
-
|
|
105
|
+
runtimeModules?: readonly AgentRuntimeModuleDefinition[];
|
|
106
|
+
/** @deprecated Use runtimeModules. */
|
|
107
|
+
denoModules?: readonly AgentRuntimeModuleDefinition[];
|
|
103
108
|
};
|
|
104
109
|
export type WebMcpSkillsInput<TTools extends readonly ToolDefinition[] = readonly ToolDefinition[]> = {
|
|
105
110
|
tools: TTools;
|
|
@@ -118,7 +123,7 @@ export type SerializableToolManifest = {
|
|
|
118
123
|
argsSchema: ToolArgsSchema;
|
|
119
124
|
timeoutMs?: number;
|
|
120
125
|
};
|
|
121
|
-
type
|
|
126
|
+
type SerializableRuntimeModuleManifest = {
|
|
122
127
|
name: string;
|
|
123
128
|
description: string;
|
|
124
129
|
usage: string;
|
|
@@ -127,10 +132,15 @@ type SerializableDenoModuleManifest = {
|
|
|
127
132
|
export type SerializableSkillsManifest = {
|
|
128
133
|
guidance: string;
|
|
129
134
|
tools: SerializableToolManifest[];
|
|
130
|
-
|
|
135
|
+
runtimeModules?: SerializableRuntimeModuleManifest[];
|
|
136
|
+
/** @deprecated Use runtimeModules. Legacy wire field. */
|
|
137
|
+
denoModules?: SerializableRuntimeModuleManifest[];
|
|
131
138
|
};
|
|
132
139
|
export type WorkspaceRunOptions = {
|
|
133
140
|
timeoutMs?: number;
|
|
141
|
+
runtimeFullAccess?: boolean;
|
|
142
|
+
runtimeModules?: readonly RuntimeModuleDefinition[];
|
|
143
|
+
/** @deprecated Use runtimeModules. */
|
|
134
144
|
denoModules?: readonly DenoModuleDefinition[];
|
|
135
145
|
};
|
|
136
146
|
export type WorkspaceRunResult = {
|
|
@@ -141,6 +151,7 @@ export type WorkspaceRunResult = {
|
|
|
141
151
|
stderrTruncated: boolean;
|
|
142
152
|
};
|
|
143
153
|
type CreateSessionSharedInput<TTools extends readonly ToolDefinition[] = readonly ToolDefinition[]> = {
|
|
154
|
+
runtimeFullAccess?: boolean;
|
|
144
155
|
skills?: SkillsInput<TTools>;
|
|
145
156
|
autoEndOnDisconnect?: boolean;
|
|
146
157
|
};
|
|
@@ -170,6 +181,8 @@ export type PedelecSettings = {
|
|
|
170
181
|
defaultProvider: ProviderCode | null;
|
|
171
182
|
};
|
|
172
183
|
export type ApprovalStatus = {
|
|
184
|
+
/** Explicit Full Runtime Access user grant reported by the Extension. */
|
|
185
|
+
runtimeFullAccessApproved?: boolean;
|
|
173
186
|
installed: boolean;
|
|
174
187
|
approved: boolean;
|
|
175
188
|
origin: string | null;
|
|
@@ -356,8 +369,10 @@ type ErrorHandler = (error: PedelecError, ctx: ErrorEventContext) => void;
|
|
|
356
369
|
type StatusHandler = (status: PedelecSessionStatus, ctx: StatusEventContext) => void;
|
|
357
370
|
type EndedHandler = (ctx: EndedEventContext) => void;
|
|
358
371
|
export declare function defineTool<TArgs = unknown, TResult = unknown, const TName extends string = string>(tool: ToolDefinition<TArgs, TResult, TName>): ToolDefinition<TArgs, TResult, TName>;
|
|
359
|
-
export declare function
|
|
360
|
-
|
|
372
|
+
export declare function defineRuntimeModule<const TModule extends RuntimeModuleDefinition>(module: TModule): TModule;
|
|
373
|
+
/** @deprecated Use defineRuntimeModule. */
|
|
374
|
+
export declare const defineDenoModule: typeof defineRuntimeModule;
|
|
375
|
+
type PreparedWorkspaceRuntimeModule = {
|
|
361
376
|
name: string;
|
|
362
377
|
runtimeSource: string;
|
|
363
378
|
typesSource: string;
|
|
@@ -388,6 +403,9 @@ export declare class Pedelec {
|
|
|
388
403
|
private readonly pageWindow;
|
|
389
404
|
private readonly channelId;
|
|
390
405
|
private readonly bridgeTimeoutMs;
|
|
406
|
+
private readonly runtimeFullAccess;
|
|
407
|
+
/** @internal */
|
|
408
|
+
get runtimeFullAccessInternal(): boolean;
|
|
391
409
|
private readonly pendingRequests;
|
|
392
410
|
private readonly sessions;
|
|
393
411
|
private readonly lastSeqBySession;
|
|
@@ -403,7 +421,7 @@ export declare class Pedelec {
|
|
|
403
421
|
createSessionInternal<const TTools extends readonly ToolDefinition[]>(input?: CreateSessionInput<TTools>, workspace?: PedelecWorkspace): Promise<PedelecSession<ToolNameOf<TTools>>>;
|
|
404
422
|
private uploadDenoModuleArtifact;
|
|
405
423
|
/** @internal */
|
|
406
|
-
uploadWorkspaceDenoModuleArtifact(workspaceId: string, module:
|
|
424
|
+
uploadWorkspaceDenoModuleArtifact(workspaceId: string, module: PreparedWorkspaceRuntimeModule): Promise<void>;
|
|
407
425
|
private uploadDenoModuleArtifactWithTicket;
|
|
408
426
|
private abortSessionSetup;
|
|
409
427
|
private completeSessionSetup;
|
package/dist/index.js
CHANGED
|
@@ -149,9 +149,23 @@ const WEBMCP_TOOL_NAME_MAX_LENGTH = 128;
|
|
|
149
149
|
export function defineTool(tool) {
|
|
150
150
|
return tool;
|
|
151
151
|
}
|
|
152
|
-
export function
|
|
152
|
+
export function defineRuntimeModule(module) {
|
|
153
153
|
return module;
|
|
154
154
|
}
|
|
155
|
+
/** @deprecated Use defineRuntimeModule. */
|
|
156
|
+
export const defineDenoModule = defineRuntimeModule;
|
|
157
|
+
function resolveRuntimeModules(options) {
|
|
158
|
+
if ("runtimeModules" in options && "denoModules" in options) {
|
|
159
|
+
throw makeError("INVALID_INPUT", "runtimeModules and denoModules cannot be combined");
|
|
160
|
+
}
|
|
161
|
+
return "runtimeModules" in options ? options.runtimeModules : options.denoModules;
|
|
162
|
+
}
|
|
163
|
+
function normalizeRuntimeFullAccess(value) {
|
|
164
|
+
if (value !== undefined && typeof value !== "boolean") {
|
|
165
|
+
throw makeError("INVALID_INPUT", "runtimeFullAccess must be a boolean");
|
|
166
|
+
}
|
|
167
|
+
return value === true;
|
|
168
|
+
}
|
|
155
169
|
function normalizeWorkspaceDenoModules(value) {
|
|
156
170
|
if (value === undefined)
|
|
157
171
|
return [];
|
|
@@ -254,7 +268,7 @@ function normalizeToolDefinitions(value, options = {}) {
|
|
|
254
268
|
}
|
|
255
269
|
function normalizeSkillsInput(value) {
|
|
256
270
|
if (value === undefined)
|
|
257
|
-
return { handlers: new Map(),
|
|
271
|
+
return { handlers: new Map(), runtimeModules: [] };
|
|
258
272
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
259
273
|
throw makeError("INVALID_INPUT", "skills must be an object");
|
|
260
274
|
}
|
|
@@ -265,12 +279,13 @@ function normalizeSkillsInput(value) {
|
|
|
265
279
|
if (!Array.isArray(skills.tools)) {
|
|
266
280
|
throw makeError("INVALID_INPUT", "skills.tools must be an array");
|
|
267
281
|
}
|
|
268
|
-
|
|
282
|
+
const modules = resolveRuntimeModules(skills);
|
|
283
|
+
if (modules !== undefined && !Array.isArray(modules)) {
|
|
269
284
|
throw makeError("INVALID_INPUT", "skills.denoModules must be an array");
|
|
270
285
|
}
|
|
271
286
|
const { tools, handlers } = normalizeToolDefinitions(skills.tools);
|
|
272
|
-
const
|
|
273
|
-
const
|
|
287
|
+
const seenRuntimeModuleNames = new Set();
|
|
288
|
+
const runtimeModules = (modules ?? []).map((module, index) => {
|
|
274
289
|
if (!module || typeof module !== "object" || Array.isArray(module)) {
|
|
275
290
|
throw makeError("INVALID_INPUT", "skills.denoModules entries must be objects", { index });
|
|
276
291
|
}
|
|
@@ -281,12 +296,12 @@ function normalizeSkillsInput(value) {
|
|
|
281
296
|
moduleName: rawModule.name,
|
|
282
297
|
});
|
|
283
298
|
}
|
|
284
|
-
if (
|
|
299
|
+
if (seenRuntimeModuleNames.has(rawModule.name)) {
|
|
285
300
|
throw makeError("INVALID_INPUT", "duplicate Deno Module name", {
|
|
286
301
|
moduleName: rawModule.name,
|
|
287
302
|
});
|
|
288
303
|
}
|
|
289
|
-
|
|
304
|
+
seenRuntimeModuleNames.add(rawModule.name);
|
|
290
305
|
if (typeof rawModule.description !== "string" || rawModule.description.trim().length === 0) {
|
|
291
306
|
throw makeError("INVALID_INPUT", "Deno Module description must be a non-empty string", {
|
|
292
307
|
moduleName: rawModule.name,
|
|
@@ -324,9 +339,10 @@ function normalizeSkillsInput(value) {
|
|
|
324
339
|
manifest: {
|
|
325
340
|
guidance: skills.guidance,
|
|
326
341
|
tools,
|
|
327
|
-
...(
|
|
342
|
+
...(runtimeModules.length > 0
|
|
328
343
|
? {
|
|
329
|
-
|
|
344
|
+
// Legacy Extension wire field; normalized data uses Runtime names.
|
|
345
|
+
denoModules: runtimeModules.map(({ name, description, usage, preferStdinExecution }) => ({
|
|
330
346
|
name,
|
|
331
347
|
description,
|
|
332
348
|
usage,
|
|
@@ -336,7 +352,7 @@ function normalizeSkillsInput(value) {
|
|
|
336
352
|
: {}),
|
|
337
353
|
},
|
|
338
354
|
handlers,
|
|
339
|
-
|
|
355
|
+
runtimeModules: runtimeModules.map(({ name, artifact }) => ({
|
|
340
356
|
name,
|
|
341
357
|
runtimeSource: artifact.runtimeSource,
|
|
342
358
|
typesSource: artifact.typesSource,
|
|
@@ -477,8 +493,13 @@ export class PedelecWorkspace {
|
|
|
477
493
|
return Promise.reject(makeError("INVALID_INPUT", "timeoutMs must be a positive integer"));
|
|
478
494
|
}
|
|
479
495
|
let modules;
|
|
496
|
+
let runtimeFullAccess;
|
|
480
497
|
try {
|
|
481
|
-
|
|
498
|
+
runtimeFullAccess = normalizeRuntimeFullAccess(options.runtimeFullAccess);
|
|
499
|
+
if (runtimeFullAccess && !this.client.runtimeFullAccessInternal) {
|
|
500
|
+
throw makeError("INVALID_INPUT", "Workspace runtimeFullAccess requires an Instance with runtimeFullAccess enabled");
|
|
501
|
+
}
|
|
502
|
+
modules = normalizeWorkspaceDenoModules(resolveRuntimeModules(options));
|
|
482
503
|
}
|
|
483
504
|
catch (error) {
|
|
484
505
|
return Promise.reject(error);
|
|
@@ -502,9 +523,10 @@ export class PedelecWorkspace {
|
|
|
502
523
|
return this.client.requestWithOptions("workspace_run", {
|
|
503
524
|
workspaceId: this.workspaceId,
|
|
504
525
|
script,
|
|
526
|
+
...(options.runtimeFullAccess === undefined ? {} : { runtimeFullAccess }),
|
|
505
527
|
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
506
528
|
...(modules.length === 0 ? {} : { denoModules: modules.map(({ name }) => name) }),
|
|
507
|
-
}, { timeoutMs: null }).then(normalizeWorkspaceRunResponse);
|
|
529
|
+
}, { timeoutMs: null }).then((value) => normalizeWorkspaceRunResponse(value, runtimeFullAccess));
|
|
508
530
|
};
|
|
509
531
|
return run();
|
|
510
532
|
}
|
|
@@ -534,6 +556,9 @@ export class Pedelec {
|
|
|
534
556
|
pageWindow;
|
|
535
557
|
channelId;
|
|
536
558
|
bridgeTimeoutMs;
|
|
559
|
+
runtimeFullAccess;
|
|
560
|
+
/** @internal */
|
|
561
|
+
get runtimeFullAccessInternal() { return this.runtimeFullAccess; }
|
|
537
562
|
pendingRequests = new Map();
|
|
538
563
|
sessions = new Map();
|
|
539
564
|
lastSeqBySession = new Map();
|
|
@@ -542,6 +567,7 @@ export class Pedelec {
|
|
|
542
567
|
pageActivityListenersAttached = false;
|
|
543
568
|
lastReportedPageActive = null;
|
|
544
569
|
constructor(options = {}) {
|
|
570
|
+
this.runtimeFullAccess = normalizeRuntimeFullAccess(options.runtimeFullAccess);
|
|
545
571
|
this.pageWindow = typeof window === "undefined" ? null : window;
|
|
546
572
|
this.channelId = createChannelId();
|
|
547
573
|
this.bridgeTimeoutMs = Math.max(1, options.bridgeTimeoutMs ?? DEFAULT_BRIDGE_TIMEOUT_MS);
|
|
@@ -591,10 +617,17 @@ export class Pedelec {
|
|
|
591
617
|
}
|
|
592
618
|
/** @internal */
|
|
593
619
|
async createSessionInternal(input = {}, workspace) {
|
|
620
|
+
const runtimeFullAccess = normalizeRuntimeFullAccess(input?.runtimeFullAccess);
|
|
621
|
+
if (runtimeFullAccess && !this.runtimeFullAccess) {
|
|
622
|
+
throw makeError("INVALID_INPUT", "Session runtimeFullAccess requires an Instance with runtimeFullAccess enabled");
|
|
623
|
+
}
|
|
624
|
+
// Admission belongs to the Extension: create_session must reach its pending
|
|
625
|
+
// approval queue so the first Full Instance request can open the Popup.
|
|
594
626
|
const resolvedOrPromise = this.resolveCreateSessionInput(input);
|
|
595
627
|
const resolvedInput = resolvedOrPromise instanceof Promise ? await resolvedOrPromise : resolvedOrPromise;
|
|
596
628
|
const result = await this.request("create_session", {
|
|
597
629
|
input: {
|
|
630
|
+
runtimeFullAccess,
|
|
598
631
|
provider: resolvedInput.provider,
|
|
599
632
|
model: resolvedInput.model,
|
|
600
633
|
effort: resolvedInput.effort,
|
|
@@ -604,6 +637,14 @@ export class Pedelec {
|
|
|
604
637
|
autoEndOnDisconnect: resolvedInput.autoEndOnDisconnect,
|
|
605
638
|
},
|
|
606
639
|
});
|
|
640
|
+
// Check the raw acknowledgment before other response validation so a known
|
|
641
|
+
// thread can still be cleaned up when a peer returns an invalid mode flag.
|
|
642
|
+
if (runtimeFullAccess && (!isPlainObject(result) || result.runtimeFullAccessApplied !== true)) {
|
|
643
|
+
if (isPlainObject(result) && typeof result.sessionId === "string" && result.sessionId.trim()) {
|
|
644
|
+
await this.abortSessionSetup(result.sessionId);
|
|
645
|
+
}
|
|
646
|
+
throw makeError("SDK_PROTOCOL_ERROR", "The connected Pedelec Extension/Desktop did not confirm Full Runtime Access", { feature: "runtimeFullAccess" });
|
|
647
|
+
}
|
|
607
648
|
const normalizedResult = normalizeCreateSessionResponse(result);
|
|
608
649
|
if (workspace && normalizedResult.workspace.workspaceId !== workspace.workspaceIdInternal) {
|
|
609
650
|
throw makeError("SDK_PROTOCOL_ERROR", "create_session response returned a different Workspace", {
|
|
@@ -617,10 +658,10 @@ export class Pedelec {
|
|
|
617
658
|
throw error;
|
|
618
659
|
}
|
|
619
660
|
try {
|
|
620
|
-
for (const module of resolvedInput.
|
|
661
|
+
for (const module of resolvedInput.runtimeModules) {
|
|
621
662
|
await this.uploadDenoModuleArtifact(normalizedResult.sessionId, module);
|
|
622
663
|
}
|
|
623
|
-
if (resolvedInput.
|
|
664
|
+
if (resolvedInput.runtimeModules.length > 0) {
|
|
624
665
|
await this.completeSessionSetup(normalizedResult.sessionId);
|
|
625
666
|
}
|
|
626
667
|
}
|
|
@@ -730,7 +771,7 @@ export class Pedelec {
|
|
|
730
771
|
async getApprovalStatus() {
|
|
731
772
|
try {
|
|
732
773
|
const result = await this.request("get_approval_status");
|
|
733
|
-
return result;
|
|
774
|
+
return { ...result, approved: result.approved === true && (!this.runtimeFullAccess || result.runtimeFullAccessApproved === true) };
|
|
734
775
|
}
|
|
735
776
|
catch (err) {
|
|
736
777
|
const error = normalizeError(err, "EXTENSION_UNAVAILABLE", "Pedelec extension is unavailable.");
|
|
@@ -885,7 +926,7 @@ export class Pedelec {
|
|
|
885
926
|
}
|
|
886
927
|
postSdkHello(port) {
|
|
887
928
|
try {
|
|
888
|
-
port.postMessage({ type: SDK_HELLO_MESSAGE_TYPE, sdkVersion: SDK_VERSION });
|
|
929
|
+
port.postMessage({ type: SDK_HELLO_MESSAGE_TYPE, sdkVersion: SDK_VERSION, runtimeFullAccess: this.runtimeFullAccess });
|
|
889
930
|
}
|
|
890
931
|
catch (err) {
|
|
891
932
|
const error = normalizeError(err, "EXTENSION_DISCONNECTED", "Pedelec extension disconnected.");
|
|
@@ -927,7 +968,7 @@ export class Pedelec {
|
|
|
927
968
|
effort,
|
|
928
969
|
skills: normalizedSkills.manifest,
|
|
929
970
|
inlineToolHandlers: normalizedSkills.handlers,
|
|
930
|
-
|
|
971
|
+
runtimeModules: normalizedSkills.runtimeModules,
|
|
931
972
|
autoEndOnDisconnect,
|
|
932
973
|
};
|
|
933
974
|
}
|
|
@@ -948,7 +989,7 @@ export class Pedelec {
|
|
|
948
989
|
effortLevel,
|
|
949
990
|
skills: normalizedSkills.manifest,
|
|
950
991
|
inlineToolHandlers: normalizedSkills.handlers,
|
|
951
|
-
|
|
992
|
+
runtimeModules: normalizedSkills.runtimeModules,
|
|
952
993
|
autoEndOnDisconnect,
|
|
953
994
|
};
|
|
954
995
|
}
|
|
@@ -1017,7 +1058,7 @@ export class Pedelec {
|
|
|
1017
1058
|
effortLevel,
|
|
1018
1059
|
skills: normalizedSkills.manifest,
|
|
1019
1060
|
inlineToolHandlers: normalizedSkills.handlers,
|
|
1020
|
-
|
|
1061
|
+
runtimeModules: normalizedSkills.runtimeModules,
|
|
1021
1062
|
autoEndOnDisconnect,
|
|
1022
1063
|
};
|
|
1023
1064
|
}
|
|
@@ -2098,12 +2139,17 @@ function normalizeWorkspaceDenoModulePrepareResponse(value, requestedNames) {
|
|
|
2098
2139
|
}
|
|
2099
2140
|
return value.missingModuleNames;
|
|
2100
2141
|
}
|
|
2101
|
-
function normalizeWorkspaceRunResponse(value) {
|
|
2142
|
+
function normalizeWorkspaceRunResponse(value, runtimeFullAccess) {
|
|
2102
2143
|
if (!isPlainObject(value) || !Number.isInteger(value.exitCode) || typeof value.stdout !== "string" ||
|
|
2103
2144
|
typeof value.stderr !== "string" || typeof value.stdoutTruncated !== "boolean" ||
|
|
2104
2145
|
typeof value.stderrTruncated !== "boolean") {
|
|
2105
2146
|
throw makeError("SDK_PROTOCOL_ERROR", "workspace_run response had an invalid shape");
|
|
2106
2147
|
}
|
|
2148
|
+
if ((runtimeFullAccess && value.runtimeFullAccessApplied !== true) ||
|
|
2149
|
+
(!runtimeFullAccess && value.runtimeFullAccessApplied === true) ||
|
|
2150
|
+
(value.runtimeFullAccessApplied !== undefined && typeof value.runtimeFullAccessApplied !== "boolean")) {
|
|
2151
|
+
throw makeError("SDK_PROTOCOL_ERROR", "The connected Pedelec Extension/Desktop did not confirm the requested Runtime mode");
|
|
2152
|
+
}
|
|
2107
2153
|
return {
|
|
2108
2154
|
exitCode: value.exitCode,
|
|
2109
2155
|
stdout: value.stdout,
|
package/dist/index.type-test.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Pedelec, defineTool, defineDenoModule, } from "./index";
|
|
1
|
+
import { Pedelec, defineTool, defineDenoModule, defineRuntimeModule, } from "./index";
|
|
2
2
|
const spriteTools = defineDenoModule({
|
|
3
3
|
name: "sprite-tools",
|
|
4
4
|
description: "Sprite authoring utilities.",
|
|
@@ -347,3 +347,24 @@ const baseContext = {
|
|
|
347
347
|
source: "sdk",
|
|
348
348
|
};
|
|
349
349
|
void baseContext;
|
|
350
|
+
const runtimeTools = defineRuntimeModule({
|
|
351
|
+
name: "runtime-tools", entry: "./helpers.ts", description: "Helpers", usage: 'import "runtime-tools";',
|
|
352
|
+
});
|
|
353
|
+
const runtimeName = runtimeTools.name;
|
|
354
|
+
const runtimeDefinition = runtimeTools;
|
|
355
|
+
void runtimeName;
|
|
356
|
+
void runtimeDefinition;
|
|
357
|
+
// @ts-expect-error Runtime Module entry is required
|
|
358
|
+
defineRuntimeModule({ name: "missing-entry" });
|
|
359
|
+
// @ts-expect-error Instance flag must be boolean
|
|
360
|
+
new Pedelec({ runtimeFullAccess: "true" });
|
|
361
|
+
async function runtimePublicContracts(workspace) {
|
|
362
|
+
const client = new Pedelec({ runtimeFullAccess: true });
|
|
363
|
+
await client.createSession({ runtimeFullAccess: true, skills: { guidance: "", tools: [], runtimeModules: [runtimeTools] } });
|
|
364
|
+
await client.createSession({ model: "model", runtimeFullAccess: true });
|
|
365
|
+
await workspace.createSession({ provider: "codex", runtimeFullAccess: true, skills: { guidance: "", tools: [], runtimeModules: [runtimeTools] } });
|
|
366
|
+
await workspace.run("", { runtimeModules: [runtimeTools] });
|
|
367
|
+
// @ts-expect-error Session flag must be boolean
|
|
368
|
+
await client.createSession({ runtimeFullAccess: 1 });
|
|
369
|
+
}
|
|
370
|
+
void runtimePublicContracts;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "0.4.
|
|
1
|
+
export declare const SDK_VERSION = "0.4.12";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated from sdk/package.json. Do not edit manually.
|
|
2
|
-
export const SDK_VERSION = "0.4.
|
|
2
|
+
export const SDK_VERSION = "0.4.12";
|
package/dist/vite.js
CHANGED
|
@@ -5,7 +5,7 @@ import * as ts from "typescript";
|
|
|
5
5
|
import { build } from "vite";
|
|
6
6
|
import { PREPARED_DENO_MODULE_ARTIFACT_PROPERTY, } from "./deno-module-internal.js";
|
|
7
7
|
const PACKAGE_NAME = "@kaoruisaac/pedelec";
|
|
8
|
-
const
|
|
8
|
+
const DEFINE_RUNTIME_MODULE_NAMES = new Set(["defineRuntimeModule", "defineDenoModule"]);
|
|
9
9
|
const ARTIFACT_HASH_VERSION = "pedelec-deno-module-artifact-v1";
|
|
10
10
|
const SCRIPT_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
11
11
|
const DECLARATION_LIKE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".d.ts", ".json"]);
|
|
@@ -913,10 +913,10 @@ function findDenoModuleImportNames(sourceFile) {
|
|
|
913
913
|
if (!namedBindings || !ts.isNamedImports(namedBindings))
|
|
914
914
|
continue;
|
|
915
915
|
for (const element of namedBindings.elements) {
|
|
916
|
-
if (element.isTypeOnly
|
|
916
|
+
if (element.isTypeOnly)
|
|
917
917
|
continue;
|
|
918
918
|
const importedName = element.propertyName?.text ?? element.name.text;
|
|
919
|
-
if (importedName
|
|
919
|
+
if (DEFINE_RUNTIME_MODULE_NAMES.has(importedName))
|
|
920
920
|
names.add(element.name.text);
|
|
921
921
|
}
|
|
922
922
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaoruisaac/pedelec",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/node": "24.13.6",
|
|
52
|
-
"vite": "8.3.
|
|
53
|
-
"vitest": "4.1.
|
|
52
|
+
"vite": "^8.3.5",
|
|
53
|
+
"vitest": "^4.1.12"
|
|
54
54
|
}
|
|
55
55
|
}
|