@github/copilot-linux-arm64
Advanced tools
| # Agent Factories | ||
| Agent Factories are extension-authored, session-scoped workflows that coordinate subagents and durable steps. The API is experimental. | ||
| ## Define and register a factory | ||
| Use `defineFactory` and pass the returned handle to `joinSession`: | ||
| ```js | ||
| import { defineFactory, joinSession } from "@github/copilot-sdk/extension"; | ||
| const reviewChanged = defineFactory({ | ||
| meta: { | ||
| name: "review-changed", | ||
| description: | ||
| "Review changed files and verify the findings. " + | ||
| "args: { files: string[] } — the paths to review.", | ||
| phases: [{ title: "Review" }, { title: "Verify" }], | ||
| limits: { | ||
| maxConcurrentSubagents: 3, | ||
| maxTotalSubagents: 10, | ||
| timeoutSeconds: 90.5, | ||
| maxAiCredits: 5, | ||
| }, | ||
| }, | ||
| run: async (ctx) => { | ||
| ctx.phase("Review"); | ||
| const reviews = await ctx.parallel( | ||
| ctx.args.files.map( | ||
| (file) => () => ctx.agent(`Review ${file}`, { label: `Review ${file}` }) | ||
| ) | ||
| ); | ||
| ctx.phase("Verify"); | ||
| const report = await ctx.step("report", () => ({ reviews })); | ||
| ctx.log(`Completed factory run ${ctx.runId}`); | ||
| return report; | ||
| }, | ||
| }); | ||
| const session = await joinSession({ factories: [reviewChanged] }); | ||
| ``` | ||
| Factory metadata contains a stable `name`, a human-readable `description`, declared `phases`, and optional `limits`. Phase entries contain a `title` and optional `detail`. | ||
| There is no declared schema for `ctx.args`. The `run_factory` tool forwards `args` verbatim and its parameter is untyped, so **the `description` is the only thing telling an agent what arguments to supply** — state the expected shape there whenever a factory reads `ctx.args`, as the example above does. Arguments supplied by an extension calling `session.factory.run(...)` directly are typed through `defineFactory<TArgs>`, but that typing does not reach the model. A factory that reads `ctx.args` should validate it rather than assume a shape. | ||
| `defineFactory<TArgs, TResult>` accepts a `run(context)` function returning `Promise<TResult>`, where `TResult` is `JsonValue | void`. Objects, arrays, strings, numbers, booleans, and `null` are valid results. Returning `undefined` completes the factory with no result. Other non-JSON values are rejected. | ||
| ## Factory context | ||
| The `run()` context provides: | ||
| - `ctx.runId`: Stable ID reused across resumed attempts. | ||
| - `ctx.args`: Invocation arguments, forwarded verbatim. When the caller omits `args`, this is `{}` rather than `undefined`. | ||
| - `ctx.agent(prompt, options?)`: Runs one factory-owned subagent. Options are exactly `label`, `schema`, and `model`. See [Subagent calls](#subagent-calls). | ||
| - `ctx.parallel(thunks)`: Runs thunks concurrently and awaits all of them (a barrier). A thunk that throws becomes `null` in the result array, so one failed item does not lose the rest. Cancellation and hard runtime failures (`ResponseError`, `ConnectionError`) are the exception — those propagate and reject the whole call, because they mean the run itself is in trouble rather than one item having failed. Handle them at run level; do not assume every failure arrives as a `null`. Rejects above 4096 items. | ||
| - `ctx.pipeline(items, ...stages)`: Flows each item through every stage without a barrier between stages, so one item can be in a later stage while another is still in an earlier one. Each stage is called as `(previous, item, index)`, where `previous` is the prior stage's result and `item` is the original input. A stage that throws drops that item to `null` and skips its remaining stages, with the same exception for cancellation and hard runtime failures. Rejects above 4096 items. | ||
| - `ctx.phase(title)`: Starts a named progress phase. This sets a single run-global value, so calling it from inside concurrent `parallel`/`pipeline` stages races. Call it at run-level transitions and distinguish concurrent work by `label` instead. | ||
| - `ctx.log(message)`: Appends a progress line. When a factory bounds its own coverage (top-N, sampling), log what was dropped. | ||
| - `ctx.step(key, producer, options?)`: Journals the producer's JSON result under a stable key so a resume replays it without re-running the producer. A journaled (default) producer must return a JSON-serializable value; `undefined` or a non-JSON value is rejected. Pass `{ volatile: true }` to bypass the journal and run the producer every time. | ||
| The key is the *sole* identity: neither the producer body nor its inputs contribute to it. A resume replays the cached value for a matching key even if the producer has since changed, so version the key (`"scan-v2"`) whenever its inputs or meaning change. Journaled producers are best-effort at-least-once and may run again across crashes or concurrent same-key callers, so keep side effects idempotent. | ||
| - `ctx.session`: The full session returned by `joinSession`. | ||
| - `ctx.signal`: Cooperative cancellation signal for extension work and subprocesses. | ||
| - `ctx.factory(...)`: Always rejects because nested factories are not supported. | ||
| Factory-owned subagents are intentionally hidden from `read_agent` and `write_agent`. Use the factory observability APIs instead. | ||
| ### Subagent calls | ||
| `ctx.agent(prompt, options?)` spawns one factory-scoped subagent and awaits it. Without a schema it resolves to the subagent's final text. With `options.schema` it resolves to the parsed JSON value. | ||
| **Identical calls are memoized into one subagent.** Each call is journaled by its canonical prompt and options, including `label`. Two calls with the same prompt and the same options return one shared result — even when issued concurrently. To spawn N *independent* subagents, give each a unique `label` or vary the prompt: | ||
| ```js | ||
| // One subagent, awaited five times — almost certainly not what you want. | ||
| await ctx.parallel([1, 2, 3, 4, 5].map(() => () => ctx.agent("Find a bug"))); | ||
| // Five independent subagents. | ||
| await ctx.parallel( | ||
| [1, 2, 3, 4, 5].map((i) => () => ctx.agent("Find a bug", { label: `finder:${i}` })) | ||
| ); | ||
| ``` | ||
| **An ordinary failure resolves to `null` — it does not throw.** A subagent that errors, returns nothing, or (with a schema) produces output that still fails to parse or match after its one retry resolves `null`. Always guard the result before using it, including a bare `await ctx.agent(...)`: | ||
| ```js | ||
| const finding = await ctx.agent(prompt, { label: "inspector" }); | ||
| if (!finding) return { finding: null }; | ||
| ``` | ||
| Cancellation and hard runtime failures — a reached limit, a durable-state failure — reject instead, aborting the run. When filtering results, prefer `v => v !== null` over `Boolean`, which also discards a valid `false`, `0`, or `""`. | ||
| **`schema` is a structural subset of JSON Schema, not a validator.** Honored: `type`, `required`, `enum`, `const`, recursive `properties`/`items`, and `anyOf`/`oneOf`/`allOf` — where `oneOf` is treated as `anyOf`, meaning at least one branch matches rather than exactly one. Ignored and *not* enforced: `additionalProperties`, `pattern`, `minLength`/`maxLength`, `format`, numeric ranges, and boolean schemas. Do not rely on an ignored keyword to constrain a result. A schema call retries once on a parse or match failure, so it may spawn twice, and both spawns count toward `maxTotalSubagents`. | ||
| ### Choosing between pipeline and parallel | ||
| Prefer `pipeline` for multi-stage work. It has no barrier between stages, so each item advances as soon as its own prior stage finishes. | ||
| Reach for a barrier — `parallel` between stages — only when a stage genuinely needs every prior result at once: deduplicating or merging across the full set, an early exit based on the total, or a prompt that compares one result against the others. Needing to map, filter, or flatten is not a reason to use a barrier; do that inside a pipeline stage. Barrier latency is real: if the slowest of N subagents takes three times the fastest, a barrier wastes the rest of the pool's time. | ||
| See [factory-patterns.md](./factory-patterns.md) for composable orchestration patterns built on these primitives. | ||
| ## Resource limits | ||
| Limits may be declared in `meta.limits` and overridden per invocation. All limits must be positive when present. | ||
| - `maxConcurrentSubagents`: Positive integer concurrent-subagent cap. Additional subagents wait in a queue. Queueing applies backpressure and does not fail the run. | ||
| - `maxTotalSubagents`: Positive integer cumulative admission cap. An attempted subagent beyond the cap ends the attempt with failure kind `maxTotalSubagents`. | ||
| - `timeoutSeconds`: Positive finite number of seconds, including positive fractions, capped at `2_147_483.647`. It measures accumulated active-execution time across attempts, including the extension body, subprocess waits, queued-agent waits, and sleeps. Time between attempts is excluded. The timeout is soft because already-running work may take time to stop. Its failure kind is `timeoutSeconds`. | ||
| - `maxAiCredits`: Positive finite AI-credit budget for the whole run's factory subagent subtree, including descendants. AI credits are GitHub Copilot's universal usage metric. This is a soft, post-paid ceiling, so completed or parallel turns can settle above it before the run stops. Accounting is fail-closed: an accounting failure stops a budgeted run rather than allowing untracked use. Its failure kind is `maxAiCredits`. | ||
| `maxTotalSubagents`, `timeoutSeconds`, and `maxAiCredits` use reject-and-retry semantics. A rejected attempt ends with run status `error` and `failure.type` set to `factory_limit_reached`. The failed run keeps its ID, arguments, journal, and accounting. Resume the run with a raised limit when additional work is approved. Previously consumed resources still count. | ||
| ## Run and resume | ||
| Run by registered name or handle: | ||
| ```ts | ||
| const run = await session.factory.run("review-changed", { | ||
| args: { files: ["src/a.ts"] }, | ||
| limits: { maxAiCredits: 3 }, | ||
| }); | ||
| if (run.status === "completed") { | ||
| console.log(run.result); | ||
| } else { | ||
| console.error(`run ${run.runId} ended as ${run.status}`, run.failure ?? run.error); | ||
| } | ||
| ``` | ||
| The name overload is: | ||
| ```ts | ||
| session.factory.run( | ||
| name: string, | ||
| options?: { args?: JsonValue; limits?: FactoryLimits }, | ||
| ): Promise<FactoryRunResult>; | ||
| ``` | ||
| Resume by run ID without resending the name or arguments: | ||
| ```ts | ||
| const run = await session.factory.resume(runId, { | ||
| limits: { maxAiCredits: 6 }, | ||
| }); | ||
| ``` | ||
| The signature is: | ||
| ```ts | ||
| session.factory.resume( | ||
| runId: string, | ||
| options?: { limits?: FactoryLimits }, | ||
| ): Promise<FactoryRunResult>; | ||
| ``` | ||
| Both resolve with the run envelope (`FactoryRunResult`) for **every** outcome — `completed`, `error`, `halted`, and `cancelled` alike. Inspect `status` and read `result` only when the run completed; a limit breach carries a typed `failure`. A declined fresh run is not a pre-execution failure: the run row already exists by the time the prompt is answered, so it resolves with a terminal `cancelled` envelope carrying the run ID. Only failures that occur *before* a run exists reject: an unknown factory name or an already-active session. Pre-execution resume failures, including a declined reapproval, throw `FactoryResumeError`, whose `code` is one of `not_found`, `non_resumable`, `already_active`, `reapproval_declined`, or `no_approval_provider`. | ||
| An agent that no longer has a prior run's ID in context can recover it with `factories_manage` and `operation: "runs"`, which lists the session's factory runs with their IDs and statuses. This matters for resume: a run that reached a limit keeps its journal, so resuming it replays completed work for free, while restarting it from scratch pays for that work twice. | ||
| The agent-facing `run_factory` tool has exactly two input branches: | ||
| ```ts | ||
| { name: string; args?: JsonValue; limits?: FactoryLimits } | ||
| { resumeFromRunId: string; limits?: FactoryLimits } | ||
| ``` | ||
| ## Authoring a factory from inside a session | ||
| The agent-facing `factories_manage` tool writes a factory into a session-scoped extension at runtime with `operation: "author"`. The rules above all apply, plus one constraint that does not affect an extension author. | ||
| **The `run` body is self-contained.** It is emitted verbatim into a generated module as a single async function expression. It closes over nothing: not the conversation that authored it, and not any authoring-time binding. Only its own locals, its `ctx` parameter, and standard Node and JavaScript globals are in scope, so every schema, constant, and helper must be defined *inside* the function. The generated module imports the SDK itself; the expression cannot add static `import` statements or use `require`. Load anything else with a dynamic `await import("...")` in the body. | ||
| ```js | ||
| async ({ args, agent, phase }) => { | ||
| // Defined inside — there is no outer scope to close over. | ||
| const VERDICT = { type: "object", properties: { real: { type: "boolean" } }, required: ["real"] }; | ||
| phase("Inspect"); | ||
| const finding = await agent(`Name one likely bug in ${args.file ?? "the code"}.`, { | ||
| label: "inspector", | ||
| }); | ||
| if (!finding) return { finding: null, real: false }; | ||
| phase("Verify"); | ||
| const verdict = await agent(`Is this a real bug? Claim: ${finding}`, { | ||
| label: "verifier", | ||
| schema: VERDICT, | ||
| }); | ||
| return { finding, real: verdict?.real === true }; | ||
| }; | ||
| ``` | ||
| Authoring registers the factory but does not run it. Invoke it afterwards with `run_factory`. Use `factories_manage` with `operation: "list"` to see the factories already registered in the session and `operation: "inspect"` to read one factory's description, phases, and limits before running it. | ||
| ## Observe a run | ||
| The calling session can inspect its own factory runs: | ||
| ```ts | ||
| const runs = await session.factory.listRuns(); | ||
| const detail = await session.factory.getRunDetail(runId); | ||
| const page = await session.factory.getRunProgress(runId, { | ||
| phaseId, | ||
| afterSeq, | ||
| beforeSeq, | ||
| limit, | ||
| }); | ||
| ``` | ||
| - `listRuns()` returns summaries in durable creation order. | ||
| - `getRunDetail(runId)` returns phases, prompt-safe agent summaries, and the latest progress page. | ||
| - `getRunProgress(runId, options?)` pages progress forward, backward, by phase, or from the latest tail. | ||
| `getRun(runId)` reads the latest run envelope, and `cancel(runId)` cancels a run and returns its terminal envelope. | ||
| `waitForRun(runId, options?)` resolves with the terminal envelope once the run settles into `completed`, `error`, `halted`, or `cancelled`, and resolves immediately when it has already settled: | ||
| ```ts | ||
| const settled = await session.factory.waitForRun(runId); | ||
| if (settled.status === "completed") { | ||
| console.log(settled.result); | ||
| } | ||
| ``` | ||
| It watches `factory.run_updated` and re-reads the durable envelope on each invalidation, collapsing a burst of events into a single in-flight read. A low-frequency periodic re-read runs alongside the subscription, so a dropped or missing invalidation degrades into a slightly late resolution rather than an unbounded wait. Pass a `signal` to stop waiting: | ||
| ```ts | ||
| const controller = new AbortController(); | ||
| setTimeout(() => controller.abort(), 30_000); | ||
| const settled = await session.factory.waitForRun(runId, { signal: controller.signal }); | ||
| ``` | ||
| Aborting rejects the wait and has no effect on the run, which keeps executing — use `cancel(runId)` to actually stop it. Because a terminal envelope is final, the resolved value never changes afterwards. `isFactoryRunTerminal(status)` exposes the same terminal-status test for callers driving their own loop. | ||
| Listen for the ephemeral `factory.run_updated` event. Its `{ runId, revision }` payload is an invalidation signal. Re-read the desired API when a newer monotonic revision arrives. | ||
| Revisions cover durable lifecycle, accounting, phase, agent, and progress changes. Continuous read-time fields can change without a new revision. These include `observedAt`, active-time calculations, live counts, and a live agent's status or prompt-safe activity text. Factory prompts are never exposed by these APIs. A run is visible only through the session that owns it. |
| # Agent Factory patterns | ||
| Composable orchestration patterns built on the factory context. Read [factories.md](./factories.md) first for the API and its semantics. The API is experimental. | ||
| Every snippet below assumes the surrounding `async (ctx) => { ... }` run body and destructures the hooks it uses. Three rules apply throughout, because breaking them fails silently: | ||
| - **Give every independent subagent a unique `label`.** Identical prompt-and-options pairs memoize into a single shared subagent. | ||
| - **Guard every `agent()` result.** An ordinary failure resolves to `null` rather than throwing. | ||
| - **Filter with `v => v !== null`,** not `Boolean`, which also discards a valid `false`, `0`, or `""`. | ||
| ## Multi-stage review | ||
| The default shape: fan out across dimensions, and let each dimension verify as soon as its own review lands. No barrier, so a slow dimension never holds up a fast one. | ||
| ```js | ||
| async ({ pipeline, parallel, agent, phase, log }) => { | ||
| const FINDINGS = { | ||
| type: "object", | ||
| properties: { | ||
| findings: { | ||
| type: "array", | ||
| items: { | ||
| type: "object", | ||
| properties: { title: { type: "string" } }, | ||
| required: ["title"], | ||
| }, | ||
| }, | ||
| }, | ||
| required: ["findings"], | ||
| }; | ||
| const VERDICT = { | ||
| type: "object", | ||
| properties: { isReal: { type: "boolean" } }, | ||
| required: ["isReal"], | ||
| }; | ||
| const DIMENSIONS = [ | ||
| { key: "bugs", prompt: "Review the diff for correctness bugs. Return JSON {findings:[{title}]}." }, | ||
| { key: "perf", prompt: "Review the diff for performance issues. Return JSON {findings:[{title}]}." }, | ||
| ]; | ||
| phase("Review"); // Run-global: set it before the fan-out, never inside a stage. | ||
| const perDimension = await pipeline( | ||
| DIMENSIONS, | ||
| (d) => agent(d.prompt, { label: `review:${d.key}`, schema: FINDINGS }), | ||
| (review, d) => { | ||
| if (!review) { | ||
| log(`review:${d.key} produced nothing`); | ||
| return []; | ||
| } | ||
| return parallel( | ||
| (review.findings ?? []).map((f, i) => () => | ||
| agent(`Adversarially verify this finding is real: ${f.title}`, { | ||
| label: `verify:${d.key}:${i}`, | ||
| schema: VERDICT, | ||
| }).then((v) => (v && v.isReal ? f : null)) | ||
| ) | ||
| ); | ||
| } | ||
| ); | ||
| return { confirmed: perDimension.flat().filter((v) => v !== null) }; | ||
| }; | ||
| ``` | ||
| ## When a barrier is correct | ||
| Deduplicating across every finding needs the whole set in hand, so the barrier earns its cost here. Dedup itself is plain JavaScript, done in the body between the two fan-outs. This excerpt reuses `FINDINGS`, `VERDICT`, and `DIMENSIONS` from the previous example — define them inside your own function. | ||
| ```js | ||
| const all = await parallel( | ||
| DIMENSIONS.map((d) => () => agent(d.prompt, { label: `find:${d.key}`, schema: FINDINGS })) | ||
| ); | ||
| const findings = all.filter((v) => v !== null).flatMap((r) => r.findings ?? []); | ||
| const deduped = [...new Map(findings.map((f) => [f.title, f])).values()]; // Needs all of them. | ||
| const verified = await parallel( | ||
| deduped.map((f, i) => () => agent(`Verify: ${f.title}`, { label: `verify:${i}`, schema: VERDICT })) | ||
| ); | ||
| ``` | ||
| ## Loop until count | ||
| Accumulate toward a target. Each iteration needs a unique identity — a unique label plus a prompt that excludes what has already been found — a bounded attempt count, and a null guard. | ||
| ```js | ||
| const BUG = { | ||
| type: "object", | ||
| properties: { title: { type: "string" } }, | ||
| required: ["title"], | ||
| }; | ||
| const bugs = []; | ||
| let attempt = 0; | ||
| while (bugs.length < 10 && attempt < 30) { | ||
| const r = await agent( | ||
| `Find ONE distinct bug NOT already listed: ${JSON.stringify(bugs.map((b) => b.title))}. Return JSON {title}.`, | ||
| { label: `finder:${attempt}`, schema: BUG } | ||
| ); | ||
| attempt++; | ||
| if (r && r.title) bugs.push(r); | ||
| log(`${bugs.length}/10 found`); | ||
| } | ||
| ``` | ||
| ## Loop until dry | ||
| Keep spawning finders until some number of consecutive rounds surface nothing new. Deduplicate against everything *seen*, not just what was kept, or discarded findings resurface every round. | ||
| ```js | ||
| const BUGS = { | ||
| type: "object", | ||
| properties: { | ||
| bugs: { | ||
| type: "array", | ||
| items: { type: "object", properties: { title: { type: "string" } }, required: ["title"] }, | ||
| }, | ||
| }, | ||
| required: ["bugs"], | ||
| }; | ||
| const VERDICT = { | ||
| type: "object", | ||
| properties: { real: { type: "boolean" } }, | ||
| required: ["real"], | ||
| }; | ||
| const seen = new Set(); | ||
| const confirmed = []; | ||
| const keyOf = (b) => b.title.toLowerCase(); | ||
| let dry = 0; | ||
| let round = 0; | ||
| while (dry < 2 && round < 20) { | ||
| const found = ( | ||
| await parallel( | ||
| [0, 1, 2].map((i) => () => | ||
| agent(`Find bugs (finder ${i}, round ${round}). Return JSON {bugs:[{title}]}.`, { | ||
| label: `find:${round}:${i}`, | ||
| schema: BUGS, | ||
| }) | ||
| ) | ||
| ) | ||
| ) | ||
| .filter((v) => v !== null) | ||
| .flatMap((r) => r.bugs ?? []); | ||
| const fresh = found.filter((b) => { | ||
| const k = keyOf(b); | ||
| if (seen.has(k)) return false; | ||
| seen.add(k); | ||
| return true; | ||
| }); | ||
| if (!fresh.length) { | ||
| dry++; | ||
| round++; | ||
| continue; | ||
| } | ||
| dry = 0; | ||
| const judged = await parallel( | ||
| fresh.map((b, i) => () => | ||
| parallel( | ||
| ["correctness", "security", "repro"].map((lens) => () => | ||
| agent(`Judge via ${lens}: is "${b.title}" real? Return JSON {real}.`, { | ||
| label: `judge:${round}:${i}:${lens}`, | ||
| schema: VERDICT, | ||
| }) | ||
| ) | ||
| ).then((vs) => ({ b, real: vs.filter((v) => v !== null).filter((v) => v.real).length >= 2 })) | ||
| ) | ||
| ); | ||
| confirmed.push(...judged.filter((v) => v !== null && v.real).map((v) => v.b)); | ||
| round++; | ||
| } | ||
| ``` | ||
| ## Quality patterns | ||
| Compose these freely. | ||
| - **Adversarial verify.** Spawn several independent skeptics per finding, each prompted to *refute* it and to default to refuted when uncertain. Keep only what a majority fails to refute. | ||
| - **Perspective-diverse verify.** Give each verifier a distinct lens — correctness, security, performance, does-it-reproduce — instead of several identical skeptics. The distinct prompts also stop them memoizing into one subagent. | ||
| - **Judge panel.** Generate several independent attempts from different angles, score them with parallel judges, then synthesize from the winner while grafting the best ideas from the runners-up. | ||
| - **Multi-modal sweep.** Run parallel searchers that each look a different way: by container, by content, by entity, by time. | ||
| - **Completeness critic.** End with an agent asking what is missing — an angle not run, a claim unverified, a source unread — and use its answer to seed the next round. | ||
| - **No silent caps.** When the factory bounds its own coverage with a top-N, a sampling step, or a no-retry rule, `log()` what was dropped. | ||
| ## Scaling | ||
| Match the orchestration to what was asked. A quick check wants a couple of subagents and single-vote verification; a request to be thorough or comprehensive wants a larger finder pool, a three-to-five vote adversarial pass, and a synthesis stage. | ||
| There is no in-script budget object. Scale with your own counters, as in the loop patterns above, and treat the declared limits as the safety ceiling rather than the control mechanism. Only `agent()` spawns are throttled, by `maxConcurrentSubagents` falling back to `maxTotalSubagents`; with neither declared there is no built-in concurrency cap, so declare one before fanning out widely. `parallel` itself is `Promise.all`, so non-agent work in a thunk runs fully concurrently regardless. | ||
| These patterns are not exhaustive. Compose novel harnesses — tournament brackets, self-repair loops, staged escalation — when the task calls for it. |
| import type { FactoryGetRunProgressRequest, FactoryProgressPage, FactoryRunDetail, FactoryRunResult as WireFactoryRunResult, FactoryRunStatus, FactoryRunSummary } from "./generated/rpc.js"; | ||
| import type { CopilotSession } from "./session.js"; | ||
| import type { FactoryLimits, FactoryMeta } from "./types.js"; | ||
| /** | ||
| * The envelope describing a factory run: its identity, status, and — once it | ||
| * has completed — its result. `getRun` returns this for an in-flight run too, | ||
| * so `status` may be `pending` or `running` and the outcome fields absent. | ||
| * | ||
| * `result` is re-typed here rather than taken from the generated wire type. The | ||
| * runtime returns any JSON value — including `null`, a string, a number, or an | ||
| * array — but the schema models the field as an opaque node, which the | ||
| * generator renders as an object. Narrowing the correction to this surface | ||
| * keeps the `x-opaque-json` handling unchanged for every other consumer. | ||
| * | ||
| * This override is temporary. Once the schema distinguishes an opaque JSON | ||
| * value from an opaque in-process value and that ships in a CLI release, | ||
| * regenerating produces the right type directly, and this declaration, the | ||
| * `toPublicFactoryRunResult` boundary helper, and the casts around it should | ||
| * all be deleted. Tracked by github/copilot-agent-runtime#14122. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export type FactoryRunResult = Omit<WireFactoryRunResult, "result"> & { | ||
| /** Completed factory result. */ | ||
| result?: JsonValue; | ||
| }; | ||
| export type { FactoryAgentSummary, FactoryPhaseStatus, FactoryPhaseObservation, FactoryProgressLine, FactoryProgressPage, FactoryRunDetail, FactoryRunStatus, FactoryRunSummary, } from "./generated/rpc.js"; | ||
| /** | ||
| * Whether a factory run status is terminal. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export declare function isFactoryRunTerminal(status: FactoryRunStatus): boolean; | ||
| declare const factoryHandleBrand: unique symbol; | ||
| /** A value that can be represented losslessly on the SDK JSON wire. */ | ||
| export type JsonValue = null | boolean | number | string | JsonValue[] | { | ||
| [key: string]: JsonValue; | ||
| }; | ||
| /** | ||
| * Conservative JSON shape language accepted for structured factory agent output. | ||
| * | ||
| * This is a best-effort structural guard used to decide whether a subagent's | ||
| * structured output should be accepted or retried — **not** a full JSON Schema | ||
| * validator. Only these keywords are honored: `type`, `required`, `enum`, | ||
| * `const`, recursive `properties`/`items`, and `anyOf`/`oneOf`/`allOf`. | ||
| * | ||
| * Everything else is **ignored, not enforced**. In particular, string | ||
| * constraints (`pattern`, `minLength`, `maxLength`, `format`), numeric ranges | ||
| * (`minimum`, `maximum`), `additionalProperties`, and boolean (`true`/`false`) | ||
| * schemas do not reject non-conforming output. `oneOf` is treated like `anyOf` | ||
| * (at least one branch must match) rather than strict exactly-one. Author | ||
| * schemas within this subset; do not rely on unsupported constraints for | ||
| * correctness. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export type FactoryJsonSchema = { | ||
| [key: string]: JsonValue; | ||
| }; | ||
| /** | ||
| * Options for one factory-scoped subagent call. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export interface FactoryAgentOptions { | ||
| label?: string; | ||
| schema?: FactoryJsonSchema; | ||
| model?: string; | ||
| } | ||
| /** | ||
| * Options for a durable factory step. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export interface FactoryStepOptions { | ||
| /** Skip the journal and always invoke the producer. */ | ||
| volatile?: boolean; | ||
| } | ||
| /** | ||
| * One stage in a per-item factory pipeline. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export type FactoryPipelineStage<TInput = unknown, TResult = unknown> = (previous: TInput, item: unknown, index: number) => Promise<TResult> | TResult; | ||
| /** | ||
| * Context passed to an extension-authored factory body. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export interface FactoryContext<TArgs extends JsonValue = JsonValue> { | ||
| /** Stable identifier for the current factory run. */ | ||
| readonly runId: string; | ||
| /** Spawn and await one factory-scoped subagent. */ | ||
| agent(prompt: string, options?: FactoryAgentOptions): Promise<unknown>; | ||
| /** Memoize an arbitrary producer under a stable author-supplied key. */ | ||
| step(key: string, producer: () => Promise<JsonValue> | JsonValue, options?: FactoryStepOptions): Promise<JsonValue>; | ||
| /** | ||
| * Run thunks concurrently and await all of them. | ||
| * | ||
| * A thunk that throws becomes `null` in the result array, so one failed | ||
| * item does not lose the rest. Cancellation and hard runtime failures | ||
| * (`ResponseError`, `ConnectionError`) are the exception: those propagate | ||
| * and reject the whole call, because they mean the run itself is in | ||
| * trouble rather than one item having failed. | ||
| */ | ||
| parallel<TResult>(thunks: Array<() => Promise<TResult> | TResult>): Promise<Array<TResult | null>>; | ||
| /** | ||
| * Run each item through every stage without barriers between stages. | ||
| * | ||
| * A stage that throws drops that item to `null` and skips its remaining | ||
| * stages. As with {@link FactoryContext.parallel}, cancellation and hard | ||
| * runtime failures propagate instead of being recorded per item. | ||
| */ | ||
| pipeline(items: unknown[], ...stages: FactoryPipelineStage[]): Promise<unknown[]>; | ||
| /** Start a named factory progress phase. */ | ||
| phase(title: string): void; | ||
| /** Emit a factory progress line. */ | ||
| log(message: string): void; | ||
| /** Reject because nested factories are not supported. */ | ||
| factory(name: string, args?: JsonValue): Promise<JsonValue | void>; | ||
| /** Caller-supplied input, forwarded verbatim. */ | ||
| args: TArgs; | ||
| /** The same full session instance returned by `joinSession`. */ | ||
| session: CopilotSession; | ||
| /** Cooperative cancellation signal for the current factory run. */ | ||
| signal: AbortSignal; | ||
| } | ||
| /** | ||
| * Definition accepted by {@link defineFactory}. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export interface FactoryDefinition<TArgs extends JsonValue = JsonValue, TResult extends JsonValue | void = JsonValue | void> { | ||
| meta: FactoryMeta; | ||
| run(context: FactoryContext<TArgs>): Promise<TResult>; | ||
| } | ||
| /** | ||
| * A deeply immutable view of a value. | ||
| * | ||
| * `defineFactory` deep-freezes the metadata it stores, so the handle's view of | ||
| * it has to be readonly all the way down or `handle.meta.name = "..."` and | ||
| * `handle.meta.phases.push(...)` would compile and then throw at runtime. | ||
| */ | ||
| type DeepReadonly<T> = T extends (infer U)[] ? readonly DeepReadonly<U>[] : T extends object ? { | ||
| readonly [K in keyof T]: DeepReadonly<T[K]>; | ||
| } : T; | ||
| /** | ||
| * Opaque reusable reference to a defined factory. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export interface FactoryHandle<TArgs extends JsonValue = JsonValue, TResult extends JsonValue | void = JsonValue | void> { | ||
| readonly meta: DeepReadonly<FactoryMeta>; | ||
| readonly [factoryHandleBrand]: { | ||
| readonly args: TArgs; | ||
| readonly result: TResult; | ||
| }; | ||
| } | ||
| /** | ||
| * Options for invoking a factory. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export interface RunOptions<TArgs extends JsonValue = JsonValue> { | ||
| /** Input surfaced as `context.args`. */ | ||
| args?: TArgs; | ||
| /** Optional per-invocation resource ceiling overrides. */ | ||
| limits?: FactoryLimits; | ||
| /** | ||
| * Prior run whose persisted identity, arguments, journal, and accounting should be resumed. | ||
| * | ||
| * @deprecated Use {@link SessionFactoryApi.resume} instead. | ||
| */ | ||
| resumeFromRunId?: string; | ||
| } | ||
| /** | ||
| * Options for resuming a factory run by ID. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export interface ResumeOptions { | ||
| /** Optional per-invocation resource ceiling overrides. */ | ||
| limits?: FactoryLimits; | ||
| } | ||
| /** | ||
| * Machine-readable pre-execution factory resume failure. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export type FactoryResumeErrorCode = "not_found" | "non_resumable" | "already_active" | "reapproval_declined" | "no_approval_provider"; | ||
| /** | ||
| * Friendly factory API exposed on a session. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export interface SessionFactoryApi { | ||
| /** | ||
| * Run a registered factory and resolve with its run envelope. | ||
| * | ||
| * The envelope is returned for every outcome, including `error`, `halted`, | ||
| * and `cancelled` — inspect `status` and read `result` only when the run | ||
| * completed. A declined fresh run resolves with a terminal `cancelled` | ||
| * envelope. Failures that occur before a run exists (such as an unknown | ||
| * factory or an already-active session) still reject. | ||
| */ | ||
| run(name: string, options?: RunOptions): Promise<FactoryRunResult>; | ||
| run<TArgs extends JsonValue>(factory: FactoryHandle<TArgs, JsonValue | void>, options?: RunOptions<TArgs>): Promise<FactoryRunResult>; | ||
| /** | ||
| * Resume a run from its persisted factory name, arguments, journal, and accounting. | ||
| * | ||
| * Resolves with the run envelope like {@link SessionFactoryApi.run}. A | ||
| * pre-execution failure, including declined reapproval, rejects with | ||
| * {@link FactoryResumeError}. | ||
| */ | ||
| resume(runId: string, options?: ResumeOptions): Promise<FactoryRunResult>; | ||
| /** Read the latest durable envelope for a factory run. */ | ||
| getRun(runId: string): Promise<FactoryRunResult>; | ||
| /** | ||
| * Wait for a run to settle and resolve with its terminal envelope. | ||
| * | ||
| * Resolves as soon as the run reaches `completed`, `error`, `halted`, or | ||
| * `cancelled`, and resolves immediately when it has already settled. A | ||
| * terminal envelope is final, so the resolved value never changes | ||
| * afterwards. | ||
| * | ||
| * This watches the run's `factory.run_updated` invalidation events and | ||
| * periodically re-reads the durable envelope so a missed event cannot | ||
| * leave the wait hanging. Pass a `signal` to stop waiting; aborting rejects | ||
| * and has no effect on the run itself, which keeps executing. Use | ||
| * {@link SessionFactoryApi.cancel} to actually stop it. | ||
| */ | ||
| waitForRun(runId: string, options?: { | ||
| signal?: AbortSignal; | ||
| }): Promise<FactoryRunResult>; | ||
| /** List this session's durable factory runs in creation order. */ | ||
| listRuns(): Promise<FactoryRunSummary[]>; | ||
| /** Read durable phases, direct agents, and the latest progress tail for a run. */ | ||
| getRunDetail(runId: string): Promise<FactoryRunDetail>; | ||
| /** Page durable progress forward, backward, or from the latest tail. */ | ||
| getRunProgress(runId: string, options?: Omit<FactoryGetRunProgressRequest, "runId">): Promise<FactoryProgressPage>; | ||
| /** Cancel a factory run and return its terminal envelope. */ | ||
| cancel(runId: string): Promise<FactoryRunResult>; | ||
| } | ||
| /** | ||
| * Error thrown when a factory cannot be resumed before execution begins. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export declare class FactoryResumeError extends Error { | ||
| readonly code: FactoryResumeErrorCode; | ||
| constructor(code: FactoryResumeErrorCode, message: string); | ||
| } | ||
| /** | ||
| * Defines an extension-authored factory and returns an opaque registration handle. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| export declare function defineFactory<TArgs extends JsonValue = JsonValue, TResult extends JsonValue | void = JsonValue | void>(definition: FactoryDefinition<TArgs, TResult>): FactoryHandle<TArgs, TResult>; |
@@ -227,2 +227,3 @@ import { createServerRpc } from "./generated/rpc.js"; | ||
| resumeSession(sessionId: string, config: ResumeSessionConfig): Promise<CopilotSession>; | ||
| private resumeSessionInternal; | ||
| /** | ||
@@ -229,0 +230,0 @@ * Sends a ping request to the server to verify connectivity. |
@@ -59,2 +59,3 @@ # Copilot CLI Extensions | ||
| - `examples.md` — Practical code examples for tools, hooks, events, and complete extensions | ||
| - `factories.md`: Authoring, running, resuming, and observing Agent Factories | ||
| - `agent-author.md` — Step-by-step workflow for agents authoring extensions programmatically |
| import type { CopilotSession } from "./session.js"; | ||
| import { type ExtensionInfo, type PermissionHandler, type ResumeSessionConfig } from "./types.js"; | ||
| import { type PermissionHandler, type ResumeSessionConfig } from "./types.js"; | ||
| import type { FactoryHandle } from "./factory.js"; | ||
| export { Canvas, CanvasError, createCanvas, type CanvasAction, type CanvasDeclaration, type CanvasHostContext, type CanvasJsonSchema, type CanvasOptions, } from "./canvas.js"; | ||
| export type JoinSessionConfig = Omit<ResumeSessionConfig, "onPermissionRequest" | "extensionSdkPath"> & { | ||
| onPermissionRequest?: PermissionHandler; | ||
| /** | ||
| * Factory handles to register when the extension joins the session. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| factories?: FactoryHandle[]; | ||
| }; | ||
| export type { ExtensionInfo }; | ||
| export type { ExtensionInfo, FactoryLimits, FactoryMeta } from "./types.js"; | ||
| export { defineFactory, FactoryResumeError, isFactoryRunTerminal, type RunOptions, type ResumeOptions, type FactoryResumeErrorCode, type SessionFactoryApi, type FactoryAgentOptions, type FactoryContext, type FactoryDefinition, type FactoryHandle, type FactoryJsonSchema, type JsonValue, type FactoryPipelineStage, type FactoryStepOptions, type FactoryRunResult, type FactoryRunStatus, type FactoryRunSummary, type FactoryRunDetail, type FactoryProgressPage, type FactoryProgressLine, type FactoryPhaseObservation, type FactoryPhaseStatus, type FactoryAgentSummary, } from "./factory.js"; | ||
| /** | ||
@@ -9,0 +18,0 @@ * Joins the current foreground session. |
@@ -10,5 +10,7 @@ /** | ||
| export { CopilotSession, type AssistantMessageEvent } from "./session.js"; | ||
| export { defineFactory, FactoryResumeError, isFactoryRunTerminal } from "./factory.js"; | ||
| export { Canvas, CanvasError, createCanvas, type CanvasAction, type CanvasDeclaration, type CanvasHostContext, type CanvasHostContextCapabilities, type CanvasJsonSchema, type CanvasOptions, } from "./canvas.js"; | ||
| export { defineTool, approveAll, convertMcpCallToolResult, createSessionFsAdapter, CopilotRequestHandler, CopilotWebSocketHandler, CopilotWebSocketCloseStatus, CopilotWebSocketForwarder, SYSTEM_MESSAGE_SECTIONS, } from "./types.js"; | ||
| export { defineTool, approveAll, convertMcpCallToolResult, createSessionFsAdapter, CopilotRequestHandler, CopilotWebSocketHandler, CopilotWebSocketCloseStatus, CopilotWebSocketForwarder, SessionFsSqliteTransactionFailure, SYSTEM_MESSAGE_SECTIONS, } from "./types.js"; | ||
| export type * from "./generated/session-events.js"; | ||
| export type { CommandContext, CommandDefinition, CommandHandler, CanvasProviderIdentity, CloudSessionOptions, CloudSessionRepository, AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, CopilotClientMode, CopilotClientOptions, StdioRuntimeConnection, InProcessRuntimeConnection, TcpRuntimeConnection, UriRuntimeConnection, ChildProcessRuntimeConnection, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, ExtensionInfo, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, GitHubTelemetryNotification, GitHubTelemetryEvent, GitHubTelemetryClientInfo, InfiniteSessionConfig, LargeToolOutputConfig, MemoryConfiguration, UiInputOptions, MCPStdioServerConfig, MCPHTTPServerConfig, MCPServerConfig, DefaultAgentConfig, BearerTokenProvider, MessageOptions, ModelBilling, ModelBillingTokenPrices, ModelBillingTokenPricesLongContext, CapiSessionOptions, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, NamedProviderConfig, PermissionHandler, PermissionRequest, PermissionRequestResult, ProviderConfig, ProviderModelConfig, ProviderTokenArgs, RemoteSessionMode, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionConfigBase, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventMetadata, SessionLifecycleEventType, SessionLifecycleHandler, SessionCreatedEvent, SessionDeletedEvent, SessionUpdatedEvent, SessionForegroundEvent, SessionBackgroundEvent, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsProvider, SessionFsFileInfo, SessionFsSqliteQueryResult, SessionFsSqliteQueryType, SessionFsSqliteProvider, CopilotRequestContext, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemMessageSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, CurrentToolMetadata, ToolTelemetry, ToolResultObject, ToolSearchConfig, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js"; | ||
| export type { CommandContext, CommandDefinition, CommandHandler, CanvasProviderIdentity, CloudSessionOptions, CloudSessionRepository, AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, AgentStopHandler, AgentStopHookInput, AgentStopHookOutput, CopilotClientMode, CopilotClientOptions, CopilotExpAssignmentResponse, StdioRuntimeConnection, InProcessRuntimeConnection, TcpRuntimeConnection, UriRuntimeConnection, ChildProcessRuntimeConnection, CustomAgentConfig, ElicitationFieldValue, ElicitationHandler, ElicitationParams, ElicitationContext, ElicitationResult, ElicitationSchema, ElicitationSchemaField, ExpConfigEntry, ExpFlagValue, ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, ExtensionInfo, ForegroundSessionInfo, GetAuthStatusResponse, GetStatusResponse, GitHubTelemetryNotification, GitHubTelemetryEvent, GitHubTelemetryClientInfo, InfiniteSessionConfig, LargeToolOutputConfig, MemoryConfiguration, UiInputOptions, FactoryLimits, FactoryMeta, MCPStdioServerConfig, MCPHTTPServerConfig, MCPServerConfig, DefaultAgentConfig, BearerTokenProvider, MessageOptions, ModelBilling, ModelBillingTokenPrices, ModelBillingTokenPricesLongContext, CapiSessionOptions, ModelCapabilities, ModelCapabilitiesOverride, ModelInfo, ModelPolicy, NamedProviderConfig, PermissionHandler, PermissionRequest, PermissionRequestResult, ProviderConfig, ProviderModelConfig, ProviderTokenArgs, RemoteSessionMode, ResumeSessionConfig, SectionOverride, SectionOverrideAction, SectionTransformFn, SessionCapabilities, SessionConfig, SessionConfigBase, SessionEvent, SessionEventHandler, SessionEventPayload, SessionEventType, SessionLifecycleEvent, SessionLifecycleEventMetadata, SessionLifecycleEventType, SessionLifecycleHandler, SessionHooks, SessionCreatedEvent, SessionDeletedEvent, SessionUpdatedEvent, SessionForegroundEvent, SessionBackgroundEvent, SessionContext, SessionListFilter, SessionMetadata, SessionUiApi, SessionFsConfig, SessionFsProvider, SessionFsFileInfo, SessionFsSqliteQueryResult, SessionFsSqliteQueryType, SessionFsSqliteProvider, SessionFsSqliteStatement, SessionFsSqliteTransactionErrorClass, CopilotRequestContext, SystemMessageAppendConfig, SystemMessageConfig, SystemMessageCustomizeConfig, SystemMessageReplaceConfig, SystemMessageSection, TelemetryConfig, TraceContext, TraceContextProvider, Tool, ToolHandler, ToolInvocation, CurrentToolMetadata, ToolTelemetry, ToolResultObject, ToolSearchConfig, TypedSessionEventHandler, TypedSessionLifecycleHandler, ZodSchema, } from "./types.js"; | ||
| export type { RunOptions, ResumeOptions, FactoryResumeErrorCode, SessionFactoryApi, FactoryAgentOptions, FactoryContext, FactoryDefinition, FactoryHandle, FactoryJsonSchema, JsonValue, FactoryPipelineStage, FactoryStepOptions, FactoryRunResult, FactoryRunStatus, FactoryRunSummary, FactoryRunDetail, FactoryProgressPage, FactoryProgressLine, FactoryPhaseObservation, FactoryPhaseStatus, FactoryAgentSummary, } from "./factory.js"; |
| import { createSessionRpc } from "./generated/rpc.js"; | ||
| import type { OpenCanvasInstance } from "./generated/rpc.js"; | ||
| import type { MessageOptions, ContextTier, ReasoningEffort, ReasoningSummary, ModelCapabilitiesOverride, SessionCapabilities, SessionEvent, SessionEventHandler, SessionEventType, SessionUiApi, TypedSessionEventHandler } from "./types.js"; | ||
| import { type SessionFactoryApi } from "./factory.js"; | ||
| /** Assistant message event - the final response from the assistant. */ | ||
@@ -48,2 +49,4 @@ export type AssistantMessageEvent = Extract<SessionEvent, { | ||
| private commandHandlers; | ||
| private factories; | ||
| private factoryAbortControllers; | ||
| private permissionHandler?; | ||
@@ -63,2 +66,20 @@ private mcpAuthHandler?; | ||
| /** | ||
| * Friendly factory API for running registered factories by name or handle. | ||
| * | ||
| * @experimental Part of the experimental Agent Factories surface and may | ||
| * change or be removed in future SDK or CLI releases. | ||
| */ | ||
| readonly factory: SessionFactoryApi; | ||
| /** | ||
| * Resolve when a factory run reaches a terminal status. | ||
| * | ||
| * The subscription is installed *before* the first read so a transition | ||
| * landing between the two cannot be missed, and re-reads are serialized so | ||
| * overlapping invalidation events cannot interleave — the run's revision | ||
| * advances once per operation, so a burst of events is common and must | ||
| * collapse into a single in-flight read. A bounded periodic re-read keeps a | ||
| * dropped invalidation from leaving the wait pending forever. | ||
| */ | ||
| private waitForFactoryRun; | ||
| /** | ||
| * Typed session-scoped RPC methods. | ||
@@ -65,0 +86,0 @@ */ |
@@ -1,3 +0,3 @@ | ||
| import type { SessionFsHandler, SessionFsStatResult, SessionFsReaddirWithTypesEntry, SessionFsSqliteQueryResult as GeneratedSqliteQueryResult, SessionFsSqliteQueryType } from "./generated/rpc.js"; | ||
| export type { SessionFsSqliteQueryType }; | ||
| import type { SessionFsHandler, SessionFsStatResult, SessionFsReaddirWithTypesEntry, SessionFsSqliteQueryResult as GeneratedSqliteQueryResult, SessionFsSqliteTransactionErrorClass, SessionFsSqliteQueryType } from "./generated/rpc.js"; | ||
| export type { SessionFsSqliteQueryType, SessionFsSqliteTransactionErrorClass }; | ||
| /** | ||
@@ -16,2 +16,27 @@ * File metadata returned by {@link SessionFsProvider.stat}. | ||
| /** | ||
| * One statement in an atomic SQLite transaction passed to | ||
| * {@link SessionFsSqliteProvider.transaction}. | ||
| */ | ||
| export interface SessionFsSqliteStatement { | ||
| /** How to execute: `"exec"` for DDL/multi-statement, `"query"` for SELECT, `"run"` for INSERT/UPDATE/DELETE. */ | ||
| queryType: SessionFsSqliteQueryType; | ||
| /** SQL statement to execute. */ | ||
| query: string; | ||
| /** Optional named bind parameters. */ | ||
| params?: Record<string, string | number | null>; | ||
| } | ||
| /** | ||
| * Error thrown by {@link SessionFsSqliteProvider.transaction} to classify a | ||
| * transaction failure for the runtime. | ||
| * | ||
| * Any other thrown value is reported as `"fatal"`. Throw this with | ||
| * `"busyOrLocked"` when SQLite reported BUSY/LOCKED before commit and the | ||
| * transaction was rolled back, so the runtime knows the call is safe to retry. | ||
| */ | ||
| export declare class SessionFsSqliteTransactionFailure extends Error { | ||
| /** Failure classification reported to the runtime. */ | ||
| readonly errorClass: SessionFsSqliteTransactionErrorClass; | ||
| constructor(message: string, errorClass?: SessionFsSqliteTransactionErrorClass); | ||
| } | ||
| /** | ||
| * SQLite operations for the per-session database. | ||
@@ -30,2 +55,13 @@ * Implementers provide query execution and existence checking. | ||
| /** | ||
| * Execute `statements` atomically against the per-session database. | ||
| * | ||
| * Apply busy handling to every statement and roll back the whole batch if | ||
| * any statement fails. Throw {@link SessionFsSqliteTransactionFailure} to | ||
| * classify the failure; any other thrown value is reported as `"fatal"`. | ||
| * | ||
| * @param statements - Statements to execute in order inside a single transaction. | ||
| * @returns One result per statement, in the same order. | ||
| */ | ||
| transaction?(statements: SessionFsSqliteStatement[]): Promise<SessionFsSqliteQueryResult[]>; | ||
| /** | ||
| * Check whether the per-session database already exists, without creating it. | ||
@@ -32,0 +68,0 @@ */ |
+1
-1
@@ -9,3 +9,3 @@ #!/usr/bin/env node | ||
| var Ve=Object.create;var M=Object.defineProperty;var Ue=Object.getOwnPropertyDescriptor;var je=Object.getOwnPropertyNames;var We=Object.getPrototypeOf,qe=Object.prototype.hasOwnProperty;var B=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(r,t)=>(typeof require<"u"?require:r)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var E=(e,r)=>()=>{try{return r||e((r={exports:{}}).exports,r),r.exports}catch(t){throw r=0,t}};var Ge=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of je(r))!qe.call(e,o)&&o!==t&&M(e,o,{get:()=>r[o],enumerable:!(n=Ue(r,o))||n.enumerable});return e};var Ke=(e,r,t)=>(t=e!=null?Ve(We(e)):{},Ge(r||!e||!e.__esModule?M(t,"default",{value:e,enumerable:!0}):t,e));var X=E((Jr,z)=>{"use strict";var Y=()=>process.platform==="linux",C=null,Ze=()=>{if(!C)if(Y()&&process.report){let e=process.report.excludeNetwork;process.report.excludeNetwork=!0,C=process.report.getReport(),process.report.excludeNetwork=e}else C={};return C};z.exports={isLinux:Y,getReport:Ze}});var Z=E((Yr,Q)=>{"use strict";var y=B("fs"),er="/usr/bin/ldd",rr="/proc/self/exe",P=2048,tr=e=>{let r=y.openSync(e,"r"),t=Buffer.alloc(P),n=y.readSync(r,t,0,P,0);return y.close(r,()=>{}),t.subarray(0,n)},nr=e=>new Promise((r,t)=>{y.open(e,"r",(n,o)=>{if(n)t(n);else{let i=Buffer.alloc(P);y.read(o,i,0,P,0,(s,c)=>{r(i.subarray(0,c)),y.close(o,()=>{})})}})});Q.exports={LDD_PATH:er,SELF_PATH:rr,readFileSync:tr,readFile:nr}});var re=E((zr,ee)=>{"use strict";var or=e=>{if(e.length<64||e.readUInt32BE(0)!==2135247942||e.readUInt8(4)!==2||e.readUInt8(5)!==1)return null;let r=e.readUInt32LE(32),t=e.readUInt16LE(54),n=e.readUInt16LE(56);for(let o=0;o<n;o++){let i=r+o*t;if(e.readUInt32LE(i)===3){let c=e.readUInt32LE(i+8),h=e.readUInt32LE(i+32);return e.subarray(c,c+h).toString().replace(/\0.*$/g,"")}}return null};ee.exports={interpreterPath:or}});var Ee=E((Xr,ve)=>{"use strict";var ne=B("child_process"),{isLinux:b,getReport:oe}=X(),{LDD_PATH:L,SELF_PATH:ie,readFile:w,readFileSync:I}=Z(),{interpreterPath:se}=re(),u,f,d,ae="getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true",m="",ce=()=>m||new Promise(e=>{ne.exec(ae,(r,t)=>{m=r?" ":t,e(m)})}),le=()=>{if(!m)try{m=ne.execSync(ae,{encoding:"utf8"})}catch{m=" "}return m},p="glibc",ue=/LIBC[a-z0-9 \-).]*?(\d+\.\d+)/i,g="musl",ir=e=>e.includes("libc.musl-")||e.includes("ld-musl-"),fe=()=>{let e=oe();return e.header&&e.header.glibcVersionRuntime?p:Array.isArray(e.sharedObjects)&&e.sharedObjects.some(ir)?g:null},de=e=>{let[r,t]=e.split(/[\r\n]+/);return r&&r.includes(p)?p:t&&t.includes(g)?g:null},pe=e=>{if(e){if(e.includes("/ld-musl-"))return g;if(e.includes("/ld-linux-"))return p}return null},me=e=>(e=e.toString(),e.includes("musl")?g:e.includes("GNU C Library")?p:null),sr=async()=>{if(f!==void 0)return f;f=null;try{let e=await w(L);f=me(e)}catch{}return f},ar=()=>{if(f!==void 0)return f;f=null;try{let e=I(L);f=me(e)}catch{}return f},cr=async()=>{if(u!==void 0)return u;u=null;try{let e=await w(ie),r=se(e);u=pe(r)}catch{}return u},lr=()=>{if(u!==void 0)return u;u=null;try{let e=I(ie),r=se(e);u=pe(r)}catch{}return u},ge=async()=>{let e=null;if(b()&&(e=await cr(),!e&&(e=await sr(),e||(e=fe()),!e))){let r=await ce();e=de(r)}return e},he=()=>{let e=null;if(b()&&(e=lr(),!e&&(e=ar(),e||(e=fe()),!e))){let r=le();e=de(r)}return e},ur=async()=>b()&&await ge()!==p,fr=()=>b()&&he()!==p,dr=async()=>{if(d!==void 0)return d;d=null;try{let r=(await w(L)).match(ue);r&&(d=r[1])}catch{}return d},pr=()=>{if(d!==void 0)return d;d=null;try{let r=I(L).match(ue);r&&(d=r[1])}catch{}return d},ye=()=>{let e=oe();return e.header&&e.header.glibcVersionRuntime?e.header.glibcVersionRuntime:null},te=e=>e.trim().split(/\s+/)[1],be=e=>{let[r,t,n]=e.split(/[\r\n]+/);return r&&r.includes(p)?te(r):t&&n&&t.includes(g)?te(n):null},mr=async()=>{let e=null;if(b()&&(e=await dr(),e||(e=ye()),!e)){let r=await ce();e=be(r)}return e},gr=()=>{let e=null;if(b()&&(e=pr(),e||(e=ye()),!e)){let r=le();e=be(r)}return e};ve.exports={GLIBC:p,MUSL:g,family:ge,familySync:he,isNonGlibcLinux:ur,isNonGlibcLinuxSync:fr,version:mr,versionSync:gr}});import $r from"node:module";import{dirname as Dr,join as Mr}from"node:path";import*as Be from"node:sea";import{fileURLToPath as Br,pathToFileURL as k}from"node:url";import{basename as hr,join as N}from"node:path";var V="0.0.1";import{readdir as Je,access as Ye,constants as ze}from"node:fs/promises";import{join as a,basename as U}from"node:path";import{homedir as x}from"node:os";function W(){return process.env.XDG_CACHE_HOME||a(x(),".cache")}function q(){if(process.argv.includes("--no-auto-update")||process.argv.includes("--prefer-version"))return!1;let e=process.env.COPILOT_AUTO_UPDATE;return!(e&&e.toLowerCase()==="false")}function G(){let e=process.argv.indexOf("--prefer-version");if(!(e===-1||e+1>=process.argv.length))return process.argv[e+1]}function Xe(){if(process.platform==="darwin")return a(x(),"Library","Caches","copilot");if(process.platform==="win32"){let e=process.env.LOCALAPPDATA||a(x(),".cache");return a(e,"copilot")}return a(W(),"copilot")}function K(){let e=[];return process.env.COPILOT_PKG_CACHE_HOME&&e.push(a(process.env.COPILOT_PKG_CACHE_HOME,"pkg")),process.env.COPILOT_CACHE_HOME&&e.push(a(process.env.COPILOT_CACHE_HOME,"pkg")),e.push(a(Xe(),"pkg")),e.push(a(W(),"copilot","pkg")),process.env.COPILOT_HOME&&e.push(a(process.env.COPILOT_HOME,"pkg")),e.push(a(x(),".copilot","pkg")),[...new Set(e)]}function j(e){let r=e.match(/^(\d+)\.(\d+)\.(\d+)/);if(r)return[Number(r[1]),Number(r[2]),Number(r[3])]}function Qe(e,r){let t=j(e),n=j(r);if(!t&&!n)return 0;if(!t)return-1;if(!n)return 1;for(let s=0;s<3;s++)if(t[s]!==n[s])return t[s]-n[s];let o=e.includes("-"),i=r.includes("-");return o!==i?o?-1:1:e.localeCompare(r)}async function J(e,...r){let t=[];for(let n of r){let o;try{o=await Je(n)}catch{continue}for(let i of o){let s=a(n,i);try{await Ye(a(s,e),ze.R_OK),t.push(s)}catch{continue}}}return t.sort((n,o)=>{let i=Qe(U(o),U(n));return i!==0?i:n.localeCompare(o)}),t}import{join as Ce}from"node:path";var O=Ke(Ee(),1);function S(e={}){return(e.platform??process.platform)!=="linux"?"gnu":e.detectLibcFamily?e.detectLibcFamily()==="musl"?"musl":"gnu":(0,O.familySync)()===O.MUSL?"musl":"gnu"}function A(e=process.platform,r){let t=r??(e==="linux"?S():"gnu");return e==="linux"&&t==="musl"?"linuxmusl":e}function xe(e=process.platform,r,t=process.arch){return`${A(e,r)}-${t}`}function Pe(){let e=xe();return K().flatMap(r=>[Ce(r,"universal"),Ce(r,e)])}function yr(){return process.env.COPILOT_CLI_VERSION?process.env.COPILOT_CLI_VERSION:"1.0.78-1"}async function Le(e,r){let t=N(e,"app.js"),n=yr()===V,o=G();if(r&&(o||q()&&!n)){let i=Pe(),s=await J("app.js",...i);if(o){let c=s.find(h=>hr(h)===o);c?t=N(c,"app.js"):process.stderr.write(`Warning: preferred version ${o} not found in package cache, using built-in version | ||
| var Ve=Object.create;var M=Object.defineProperty;var Ue=Object.getOwnPropertyDescriptor;var je=Object.getOwnPropertyNames;var We=Object.getPrototypeOf,qe=Object.prototype.hasOwnProperty;var B=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(r,t)=>(typeof require<"u"?require:r)[t]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var E=(e,r)=>()=>{try{return r||e((r={exports:{}}).exports,r),r.exports}catch(t){throw r=0,t}};var Ge=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of je(r))!qe.call(e,o)&&o!==t&&M(e,o,{get:()=>r[o],enumerable:!(n=Ue(r,o))||n.enumerable});return e};var Ke=(e,r,t)=>(t=e!=null?Ve(We(e)):{},Ge(r||!e||!e.__esModule?M(t,"default",{value:e,enumerable:!0}):t,e));var X=E((Jr,z)=>{"use strict";var Y=()=>process.platform==="linux",C=null,Ze=()=>{if(!C)if(Y()&&process.report){let e=process.report.excludeNetwork;process.report.excludeNetwork=!0,C=process.report.getReport(),process.report.excludeNetwork=e}else C={};return C};z.exports={isLinux:Y,getReport:Ze}});var Z=E((Yr,Q)=>{"use strict";var y=B("fs"),er="/usr/bin/ldd",rr="/proc/self/exe",P=2048,tr=e=>{let r=y.openSync(e,"r"),t=Buffer.alloc(P),n=y.readSync(r,t,0,P,0);return y.close(r,()=>{}),t.subarray(0,n)},nr=e=>new Promise((r,t)=>{y.open(e,"r",(n,o)=>{if(n)t(n);else{let i=Buffer.alloc(P);y.read(o,i,0,P,0,(s,c)=>{r(i.subarray(0,c)),y.close(o,()=>{})})}})});Q.exports={LDD_PATH:er,SELF_PATH:rr,readFileSync:tr,readFile:nr}});var re=E((zr,ee)=>{"use strict";var or=e=>{if(e.length<64||e.readUInt32BE(0)!==2135247942||e.readUInt8(4)!==2||e.readUInt8(5)!==1)return null;let r=e.readUInt32LE(32),t=e.readUInt16LE(54),n=e.readUInt16LE(56);for(let o=0;o<n;o++){let i=r+o*t;if(e.readUInt32LE(i)===3){let c=e.readUInt32LE(i+8),h=e.readUInt32LE(i+32);return e.subarray(c,c+h).toString().replace(/\0.*$/g,"")}}return null};ee.exports={interpreterPath:or}});var Ee=E((Xr,ve)=>{"use strict";var ne=B("child_process"),{isLinux:b,getReport:oe}=X(),{LDD_PATH:L,SELF_PATH:ie,readFile:w,readFileSync:I}=Z(),{interpreterPath:se}=re(),u,f,d,ae="getconf GNU_LIBC_VERSION 2>&1 || true; ldd --version 2>&1 || true",m="",ce=()=>m||new Promise(e=>{ne.exec(ae,(r,t)=>{m=r?" ":t,e(m)})}),le=()=>{if(!m)try{m=ne.execSync(ae,{encoding:"utf8"})}catch{m=" "}return m},p="glibc",ue=/LIBC[a-z0-9 \-).]*?(\d+\.\d+)/i,g="musl",ir=e=>e.includes("libc.musl-")||e.includes("ld-musl-"),fe=()=>{let e=oe();return e.header&&e.header.glibcVersionRuntime?p:Array.isArray(e.sharedObjects)&&e.sharedObjects.some(ir)?g:null},de=e=>{let[r,t]=e.split(/[\r\n]+/);return r&&r.includes(p)?p:t&&t.includes(g)?g:null},pe=e=>{if(e){if(e.includes("/ld-musl-"))return g;if(e.includes("/ld-linux-"))return p}return null},me=e=>(e=e.toString(),e.includes("musl")?g:e.includes("GNU C Library")?p:null),sr=async()=>{if(f!==void 0)return f;f=null;try{let e=await w(L);f=me(e)}catch{}return f},ar=()=>{if(f!==void 0)return f;f=null;try{let e=I(L);f=me(e)}catch{}return f},cr=async()=>{if(u!==void 0)return u;u=null;try{let e=await w(ie),r=se(e);u=pe(r)}catch{}return u},lr=()=>{if(u!==void 0)return u;u=null;try{let e=I(ie),r=se(e);u=pe(r)}catch{}return u},ge=async()=>{let e=null;if(b()&&(e=await cr(),!e&&(e=await sr(),e||(e=fe()),!e))){let r=await ce();e=de(r)}return e},he=()=>{let e=null;if(b()&&(e=lr(),!e&&(e=ar(),e||(e=fe()),!e))){let r=le();e=de(r)}return e},ur=async()=>b()&&await ge()!==p,fr=()=>b()&&he()!==p,dr=async()=>{if(d!==void 0)return d;d=null;try{let r=(await w(L)).match(ue);r&&(d=r[1])}catch{}return d},pr=()=>{if(d!==void 0)return d;d=null;try{let r=I(L).match(ue);r&&(d=r[1])}catch{}return d},ye=()=>{let e=oe();return e.header&&e.header.glibcVersionRuntime?e.header.glibcVersionRuntime:null},te=e=>e.trim().split(/\s+/)[1],be=e=>{let[r,t,n]=e.split(/[\r\n]+/);return r&&r.includes(p)?te(r):t&&n&&t.includes(g)?te(n):null},mr=async()=>{let e=null;if(b()&&(e=await dr(),e||(e=ye()),!e)){let r=await ce();e=be(r)}return e},gr=()=>{let e=null;if(b()&&(e=pr(),e||(e=ye()),!e)){let r=le();e=be(r)}return e};ve.exports={GLIBC:p,MUSL:g,family:ge,familySync:he,isNonGlibcLinux:ur,isNonGlibcLinuxSync:fr,version:mr,versionSync:gr}});import $r from"node:module";import{dirname as Dr,join as Mr}from"node:path";import*as Be from"node:sea";import{fileURLToPath as Br,pathToFileURL as k}from"node:url";import{basename as hr,join as N}from"node:path";var V="0.0.1";import{readdir as Je,access as Ye,constants as ze}from"node:fs/promises";import{join as a,basename as U}from"node:path";import{homedir as x}from"node:os";function W(){return process.env.XDG_CACHE_HOME||a(x(),".cache")}function q(){if(process.argv.includes("--no-auto-update")||process.argv.includes("--prefer-version"))return!1;let e=process.env.COPILOT_AUTO_UPDATE;return!(e&&e.toLowerCase()==="false")}function G(){let e=process.argv.indexOf("--prefer-version");if(!(e===-1||e+1>=process.argv.length))return process.argv[e+1]}function Xe(){if(process.platform==="darwin")return a(x(),"Library","Caches","copilot");if(process.platform==="win32"){let e=process.env.LOCALAPPDATA||a(x(),".cache");return a(e,"copilot")}return a(W(),"copilot")}function K(){let e=[];return process.env.COPILOT_PKG_CACHE_HOME&&e.push(a(process.env.COPILOT_PKG_CACHE_HOME,"pkg")),process.env.COPILOT_CACHE_HOME&&e.push(a(process.env.COPILOT_CACHE_HOME,"pkg")),e.push(a(Xe(),"pkg")),e.push(a(W(),"copilot","pkg")),process.env.COPILOT_HOME&&e.push(a(process.env.COPILOT_HOME,"pkg")),e.push(a(x(),".copilot","pkg")),[...new Set(e)]}function j(e){let r=e.match(/^(\d+)\.(\d+)\.(\d+)/);if(r)return[Number(r[1]),Number(r[2]),Number(r[3])]}function Qe(e,r){let t=j(e),n=j(r);if(!t&&!n)return 0;if(!t)return-1;if(!n)return 1;for(let s=0;s<3;s++)if(t[s]!==n[s])return t[s]-n[s];let o=e.includes("-"),i=r.includes("-");return o!==i?o?-1:1:e.localeCompare(r)}async function J(e,...r){let t=[];for(let n of r){let o;try{o=await Je(n)}catch{continue}for(let i of o){let s=a(n,i);try{await Ye(a(s,e),ze.R_OK),t.push(s)}catch{continue}}}return t.sort((n,o)=>{let i=Qe(U(o),U(n));return i!==0?i:n.localeCompare(o)}),t}import{join as Ce}from"node:path";var O=Ke(Ee(),1);function S(e={}){return(e.platform??process.platform)!=="linux"?"gnu":e.detectLibcFamily?e.detectLibcFamily()==="musl"?"musl":"gnu":(0,O.familySync)()===O.MUSL?"musl":"gnu"}function A(e=process.platform,r){let t=r??(e==="linux"?S():"gnu");return e==="linux"&&t==="musl"?"linuxmusl":e}function xe(e=process.platform,r,t=process.arch){return`${A(e,r)}-${t}`}function Pe(){let e=xe();return K().flatMap(r=>[Ce(r,"universal"),Ce(r,e)])}function yr(){return process.env.COPILOT_CLI_VERSION?process.env.COPILOT_CLI_VERSION:"1.0.78-2"}async function Le(e,r){let t=N(e,"app.js"),n=yr()===V,o=G();if(r&&(o||q()&&!n)){let i=Pe(),s=await J("app.js",...i);if(o){let c=s.find(h=>hr(h)===o);c?t=N(c,"app.js"):process.stderr.write(`Warning: preferred version ${o} not found in package cache, using built-in version | ||
| `)}else s.length>0&&(t=N(s[0],"app.js"))}return t}import{existsSync as br}from"node:fs";import{basename as vr,resolve as Er}from"node:path";var Oe="extension_bootstrap.mjs";function Se(e,r,t=br){let n=e.find(s=>vr(s)===Oe);if(!n)return;process.stderr.write(`[extension-fork] resolveBootstrapPath: __dir=${r}, argv-bootstrap=${n} | ||
@@ -12,0 +12,0 @@ `);let o=Er(r,"preloads",Oe),i=t(o);if(process.stderr.write(`[extension-fork] resolveBootstrapPath: localBootstrap=${o}, localExists=${i} |
+1
-1
| { | ||
| "name": "@github/copilot-linux-arm64", | ||
| "version": "1.0.78-1", | ||
| "version": "1.0.78-2", | ||
| "description": "GitHub Copilot CLI for linux-arm64", | ||
@@ -5,0 +5,0 @@ "license": "SEE LICENSE IN LICENSE.md", |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 6 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 6 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
379545780
0.25%227
1.34%183204
3.42%279
0.36%