@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 CHANGED
@@ -91,9 +91,9 @@ npm install ../path/to/pedelec/sdk
91
91
 
92
92
  ---
93
93
 
94
- ## Deno Modules
94
+ ## Runtime Modules
95
95
 
96
- Vite applications can package local or installed JavaScript/TypeScript libraries for Agent-authored `pedelec-deno` scripts.
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, defineDenoModule } from "@kaoruisaac/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
- denoModules: [
121
- defineDenoModule({
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
- defineDenoModule({
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
- Deno Modules are imported inside JavaScript/TypeScript run with `pedelec-deno`. They are different from `skills.tools`, whose browser/App RPC capabilities use `pedelec-cli` tool-spec and tool-call commands.
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 the optional `preferStdinExecution: true` when short scripts primarily use a module and should be steered toward stdin execution. Host Context then adds that module's concrete `runCommandTemplate` (`@'\n<typescript-source>\n'@ | pedelec-deno --thread-id <thread-id> run -`), so the Agent only needs to replace the TypeScript source placeholder instead of deciding how to serialize stdin. This is a preference, not a restriction: file-backed execution remains valid, and omitting the field or setting it to `false` preserves the default behavior. It does not change bundling, artifact contents, or runtime permissions.
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 Deno 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.
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 Deno code in the Workspace:
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. The existing no-remote, cached-only, and no-npm runtime restrictions still apply. This is a direct deterministic capability for an approved Web application to read and modify the opened Workspace; it is not unrestricted host code execution and is not mediated by an Agent.
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.denoModules` belong to the Session/Thread that declares them and are available only to Agent-side `pedelec-deno` execution for that Thread. Workspace runs accept the same Vite-prepared declarations explicitly:
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 = defineDenoModule({
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
- { denoModules: [sceneTools] },
372
+ { runtimeModules: [sceneTools] },
373
373
  );
374
374
  ```
375
375
 
376
- `workspace.run()` does not inherit any Session Deno 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.
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 Deno 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.
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 DenoModuleDefinition<TName extends string = string> = {
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
- type AgentDenoModuleDefinition<TName extends string = string> = DenoModuleDefinition<TName> & {
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
- denoModules?: readonly AgentDenoModuleDefinition[];
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 SerializableDenoModuleManifest = {
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
- denoModules?: SerializableDenoModuleManifest[];
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 defineDenoModule<const TModule extends DenoModuleDefinition>(module: TModule): TModule;
360
- type PreparedWorkspaceDenoModule = {
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: PreparedWorkspaceDenoModule): Promise<void>;
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 defineDenoModule(module) {
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(), denoModules: [] };
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
- if (skills.denoModules !== undefined && !Array.isArray(skills.denoModules)) {
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 seenDenoModuleNames = new Set();
273
- const denoModules = (skills.denoModules ?? []).map((module, index) => {
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 (seenDenoModuleNames.has(rawModule.name)) {
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
- seenDenoModuleNames.add(rawModule.name);
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
- ...(denoModules.length > 0
342
+ ...(runtimeModules.length > 0
328
343
  ? {
329
- denoModules: denoModules.map(({ name, description, usage, preferStdinExecution }) => ({
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
- denoModules: denoModules.map(({ name, artifact }) => ({
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
- modules = normalizeWorkspaceDenoModules(options.denoModules);
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.denoModules) {
661
+ for (const module of resolvedInput.runtimeModules) {
621
662
  await this.uploadDenoModuleArtifact(normalizedResult.sessionId, module);
622
663
  }
623
- if (resolvedInput.denoModules.length > 0) {
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
- denoModules: normalizedSkills.denoModules,
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
- denoModules: normalizedSkills.denoModules,
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
- denoModules: normalizedSkills.denoModules,
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,
@@ -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.10";
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.10";
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 DEFINE_DENO_MODULE_NAME = "defineDenoModule";
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 || element.propertyName?.text !== DEFINE_DENO_MODULE_NAME && element.name.text !== DEFINE_DENO_MODULE_NAME)
916
+ if (element.isTypeOnly)
917
917
  continue;
918
918
  const importedName = element.propertyName?.text ?? element.name.text;
919
- if (importedName === DEFINE_DENO_MODULE_NAME)
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.10",
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.0",
53
- "vitest": "4.1.11"
52
+ "vite": "^8.3.5",
53
+ "vitest": "^4.1.12"
54
54
  }
55
55
  }