From 9a07e586cf062f723f243757d7c5244540e207ca Mon Sep 17 00:00:00 2001 From: Steffen Beyer Date: Sat, 4 Apr 2026 11:17:36 +0200 Subject: [PATCH] chore: prepare pigibrack npm package release --- .pi/extensions/pigibrack/index.ts | 1077 +---------------- LICENSE | 25 + README.md | 50 + .../pigibrack/README.md | 12 +- .../pigibrack/guile/check_syntax.scm | 0 .../pigibrack/guile/eval_expr.scm | 0 .../pigibrack/guile/repl_sidecar.scm | 0 extensions/pigibrack/index.ts | 1076 ++++++++++++++++ package-lock.json | 181 +-- package.json | 28 +- 10 files changed, 1192 insertions(+), 1257 deletions(-) create mode 100644 LICENSE create mode 100644 README.md rename {.pi/extensions => extensions}/pigibrack/README.md (87%) rename {.pi/extensions => extensions}/pigibrack/guile/check_syntax.scm (100%) rename {.pi/extensions => extensions}/pigibrack/guile/eval_expr.scm (100%) rename {.pi/extensions => extensions}/pigibrack/guile/repl_sidecar.scm (100%) create mode 100644 extensions/pigibrack/index.ts diff --git a/.pi/extensions/pigibrack/index.ts b/.pi/extensions/pigibrack/index.ts index cf67922..ae9d1fc 100644 --- a/.pi/extensions/pigibrack/index.ts +++ b/.pi/extensions/pigibrack/index.ts @@ -1,1076 +1 @@ -import { StringEnum, Type } from '@mariozechner/pi-ai'; -import { - DEFAULT_MAX_BYTES, - DEFAULT_MAX_LINES, - formatSize, - truncateHead, - truncateTail, - withFileMutationQueue, - type ExtensionAPI, -} from '@mariozechner/pi-coding-agent'; -import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'; -import { existsSync } from 'node:fs'; -import { mkdtemp, readFile, writeFile } from 'node:fs/promises'; -import { tmpdir } from 'node:os'; -import { join, resolve } from 'node:path'; -import { createInterface } from 'node:readline'; - -const CHECK_SYNTAX_SCRIPT = resolve(__dirname, 'guile/check_syntax.scm'); -const EVAL_EXPR_SCRIPT = resolve(__dirname, 'guile/eval_expr.scm'); -const REPL_SIDECAR_SCRIPT = resolve(__dirname, 'guile/repl_sidecar.scm'); - -const TOOL_DESCRIPTION_SUFFIX = `Tool output is truncated to ${DEFAULT_MAX_LINES} lines or ${formatSize(DEFAULT_MAX_BYTES)}.`; - -interface FormSpan { - start: number; - end: number; - line: number; - text: string; - name?: string; -} - -interface SyntaxCheckResult { - valid: boolean; - errors: string[]; -} - -interface EvalResult { - stdout: string; - value: string; -} - -interface SidecarWaiter { - resolve: (line: string) => void; - reject: (error: Error) => void; -} - -interface ReplSidecar { - process: ChildProcessWithoutNullStreams; - cwd: string; - lines: string[]; - waiters: SidecarWaiter[]; - queue: Promise; - stderrTail: string[]; - closedError?: Error; -} - -function normalizeUserPath(path: string): string { - return path.startsWith('@') ? path.slice(1) : path; -} - -function lineNumberAt(source: string, index: number): number { - let line = 1; - for (let i = 0; i < index && i < source.length; i += 1) { - if (source[i] === '\n') line += 1; - } - return line; -} - -function isWhitespace(ch: string | undefined): boolean { - return ch === ' ' || ch === '\n' || ch === '\r' || ch === '\t' || ch === '\f'; -} - -function isDelimiter(ch: string | undefined): boolean { - if (ch === undefined) return true; - return ( - isWhitespace(ch) || - ch === '(' || - ch === ')' || - ch === '[' || - ch === ']' || - ch === '"' || - ch === ';' - ); -} - -function parseTopLevelForms(source: string): FormSpan[] { - const len = source.length; - - function skipLineComment(i: number): number { - let cursor = i; - while (cursor < len && source[cursor] !== '\n') cursor += 1; - return cursor; - } - - function skipBlockComment(i: number): number { - let cursor = i + 2; - let depth = 1; - - while (cursor < len - 1) { - if (source[cursor] === '#' && source[cursor + 1] === '|') { - depth += 1; - cursor += 2; - continue; - } - if (source[cursor] === '|' && source[cursor + 1] === '#') { - depth -= 1; - cursor += 2; - if (depth === 0) return cursor; - continue; - } - cursor += 1; - } - - throw new Error('Unterminated block comment (#| ... |#).'); - } - - function parseString(i: number): number { - let cursor = i + 1; - let escaped = false; - - while (cursor < len) { - const ch = source[cursor]; - if (escaped) { - escaped = false; - } else if (ch === '\\') { - escaped = true; - } else if (ch === '"') { - return cursor + 1; - } - cursor += 1; - } - - throw new Error('Unterminated string literal.'); - } - - function parseAtom(i: number): number { - let cursor = i; - - while (cursor < len) { - const ch = source[cursor]; - if (isDelimiter(ch)) break; - if (ch === '#' && (source[cursor + 1] === '|' || source[cursor + 1] === ';')) break; - cursor += 1; - } - - if (cursor === i) throw new Error(`Unexpected token at index ${i}.`); - return cursor; - } - - function skipTrivia(i: number): number { - let cursor = i; - - while (cursor < len) { - const ch = source[cursor]; - - if (isWhitespace(ch)) { - cursor += 1; - continue; - } - - if (ch === ';') { - cursor = skipLineComment(cursor); - continue; - } - - if (ch === '#' && source[cursor + 1] === '|') { - cursor = skipBlockComment(cursor); - continue; - } - - if (ch === '#' && source[cursor + 1] === ';') { - cursor += 2; - cursor = skipTrivia(cursor); - cursor = parseDatum(cursor); - continue; - } - - break; - } - - return cursor; - } - - function parseList(i: number): number { - const open = source[i]; - const close = open === '(' ? ')' : ']'; - let cursor = i + 1; - - while (cursor < len) { - cursor = skipTrivia(cursor); - if (cursor >= len) break; - - if (source[cursor] === close) return cursor + 1; - if (source[cursor] === ')' || source[cursor] === ']') { - throw new Error(`Mismatched list delimiter near index ${cursor}.`); - } - - cursor = parseDatum(cursor); - } - - throw new Error('Unterminated list form.'); - } - - function parseDatum(i: number): number { - const cursor = skipTrivia(i); - if (cursor >= len) throw new Error('Unexpected end of input.'); - - const ch = source[cursor]; - - if (ch === '(' || ch === '[') { - return parseList(cursor); - } - - if (ch === '"') { - return parseString(cursor); - } - - if (ch === "'" || ch === '`') { - return parseDatum(cursor + 1); - } - - if (ch === ',') { - return parseDatum(source[cursor + 1] === '@' ? cursor + 2 : cursor + 1); - } - - if (ch === '#') { - if (source[cursor + 1] === '(' || source[cursor + 1] === '[') { - return parseList(cursor + 1); - } - - let maybeVectorCursor = cursor + 1; - while (/[a-zA-Z0-9]/.test(source[maybeVectorCursor] ?? '')) maybeVectorCursor += 1; - if (source[maybeVectorCursor] === '(' || source[maybeVectorCursor] === '[') { - return parseList(maybeVectorCursor); - } - } - - return parseAtom(cursor); - } - - const forms: FormSpan[] = []; - let cursor = skipTrivia(0); - - while (cursor < len) { - const start = cursor; - const end = parseDatum(cursor); - const text = source.slice(start, end); - - forms.push({ - start, - end, - line: lineNumberAt(source, start), - text, - name: extractFormName(text), - }); - - cursor = skipTrivia(end); - } - - return forms; -} - -function extractFormName(formText: string): string | undefined { - const trimmed = formText.trim(); - if (!trimmed.startsWith('(')) return undefined; - - const patterns = [ - /^\(\s*(?:define|define-public|define\*)\s+\(([^\s()\[\]]+)/, - /^\(\s*(?:define|define-public|define\*)\s+([^\s()\[\]]+)/, - /^\(\s*(?:define-syntax|define-syntax-rule|define-macro)\s+\(([^\s()\[\]]+)/, - /^\(\s*(?:define-syntax|define-syntax-rule|define-macro)\s+([^\s()\[\]]+)/, - /^\(\s*define-record-type\s+([^\s()\[\]]+)/, - /^\(\s*define-class\s+([^\s()\[\]]+)/, - ]; - - for (const pattern of patterns) { - const match = trimmed.match(pattern); - if (match?.[1]) return match[1]; - } - - return undefined; -} - -function oneLine(text: string): string { - return text.replace(/\s+/g, ' ').trim(); -} - -function collapseForm(formText: string): string { - const trimmed = formText.trim(); - const lines = trimmed.split('\n'); - - let output = lines.length <= 5 ? oneLine(trimmed) : `${oneLine(lines[0] ?? trimmed)} ...`; - - if (output.length > 160) { - output = `${output.slice(0, 157)}...`; - } - - return output; -} - -function uniqueByName(forms: FormSpan[], name: string): FormSpan { - const matches = forms.filter((form) => form.name === name); - - if (matches.length === 0) { - const available = Array.from(new Set(forms.map((form) => form.name).filter(Boolean))).slice( - 0, - 30, - ) as string[]; - const suffix = available.length > 0 ? ` Available names: ${available.join(', ')}` : ''; - throw new Error(`No top-level form named "${name}" found.${suffix}`); - } - - if (matches.length > 1) { - const locations = matches.map((match) => `line ${match.line}`).join(', '); - throw new Error( - `Multiple forms named "${name}" found (${locations}). Please disambiguate first.`, - ); - } - - return matches[0]; -} - -function ensureSingleTopLevelForm(source: string): string { - const trimmed = source.trim(); - if (!trimmed) throw new Error('newSource is empty.'); - - const forms = parseTopLevelForms(trimmed); - if (forms.length !== 1 || forms[0].start !== 0 || forms[0].end !== trimmed.length) { - throw new Error('newSource must contain exactly one top-level form.'); - } - - return trimmed; -} - -function formatTruncated(text: string, mode: 'head' | 'tail' = 'head'): string { - const truncation = - mode === 'head' - ? truncateHead(text, { maxLines: DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES }) - : truncateTail(text, { maxLines: DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES }); - - let output = truncation.content; - if (truncation.truncated) { - output += `\n\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines, ${formatSize(truncation.outputBytes)}/${formatSize(truncation.totalBytes)}.]`; - } - - return output; -} - -function parseEvalOutput(raw: string): EvalResult { - const stdoutStart = '__PIGI_STDOUT_START__\n'; - const stdoutEnd = '__PIGI_STDOUT_END__\n'; - const resultStart = '__PIGI_RESULT_START__\n'; - const resultEnd = '__PIGI_RESULT_END__\n'; - - const stdoutStartIndex = raw.indexOf(stdoutStart); - const stdoutEndIndex = raw.indexOf(stdoutEnd); - const resultStartIndex = raw.indexOf(resultStart); - const resultEndIndex = raw.indexOf(resultEnd); - - if ( - stdoutStartIndex === -1 || - stdoutEndIndex === -1 || - resultStartIndex === -1 || - resultEndIndex === -1 - ) { - return { stdout: '', value: raw.trim() }; - } - - const stdout = raw.slice(stdoutStartIndex + stdoutStart.length, stdoutEndIndex); - const value = raw.slice(resultStartIndex + resultStart.length, resultEndIndex); - - return { stdout: stdout.trimEnd(), value: value.trimEnd() }; -} - -async function writeTempScheme(source: string): Promise { - const dir = await mkdtemp(join(tmpdir(), 'pigibrack-')); - const file = join(dir, 'input.scm'); - await writeFile(file, source, 'utf8'); - return file; -} - -export default function pigibrackExtension(pi: ExtensionAPI) { - let replSidecar: ReplSidecar | undefined; - - function closeSidecar(sidecar: ReplSidecar, error: Error) { - if (sidecar.closedError) return; - - sidecar.closedError = error; - for (const waiter of sidecar.waiters) { - waiter.reject(error); - } - sidecar.waiters = []; - - if (replSidecar === sidecar) { - replSidecar = undefined; - } - } - - function readSidecarLine(sidecar: ReplSidecar): Promise { - if (sidecar.lines.length > 0) { - return Promise.resolve(sidecar.lines.shift() as string); - } - - if (sidecar.closedError) { - return Promise.reject(sidecar.closedError); - } - - return new Promise((resolve, reject) => { - sidecar.waiters.push({ resolve, reject }); - }); - } - - async function waitForSidecarLine( - sidecar: ReplSidecar, - timeoutMs: number, - signal?: AbortSignal, - ): Promise { - const linePromise = readSidecarLine(sidecar); - - return await new Promise((resolve, reject) => { - let done = false; - - const finish = (fn: () => void) => { - if (done) return; - done = true; - clearTimeout(timeout); - if (signal) { - signal.removeEventListener('abort', onAbort); - } - fn(); - }; - - const timeout = setTimeout(() => { - finish(() => - reject(new Error(`Timed out waiting for sidecar response after ${timeoutMs}ms.`)), - ); - }, timeoutMs); - - const onAbort = () => { - finish(() => reject(new Error('Operation cancelled.'))); - }; - - if (signal) { - if (signal.aborted) { - finish(() => reject(new Error('Operation cancelled.'))); - return; - } - signal.addEventListener('abort', onAbort, { once: true }); - } - - linePromise.then( - (line) => finish(() => resolve(line)), - (error) => finish(() => reject(error)), - ); - }); - } - - function enqueueSidecar(sidecar: ReplSidecar, task: () => Promise): Promise { - const run = sidecar.queue.then(task, task); - sidecar.queue = run.then( - () => undefined, - () => undefined, - ); - return run; - } - - function createReplSidecar(cwd: string): ReplSidecar { - const process = spawn('guile', ['-L', cwd, REPL_SIDECAR_SCRIPT], { - cwd, - stdio: ['pipe', 'pipe', 'pipe'], - }); - - const sidecar: ReplSidecar = { - process, - cwd, - lines: [], - waiters: [], - queue: Promise.resolve(), - stderrTail: [], - }; - - const stdoutReader = createInterface({ input: process.stdout }); - stdoutReader.on('line', (line) => { - if (sidecar.waiters.length > 0) { - const waiter = sidecar.waiters.shift() as SidecarWaiter; - waiter.resolve(line); - } else { - sidecar.lines.push(line); - } - }); - - process.stderr.on('data', (chunk) => { - const text = String(chunk); - for (const line of text.split('\n')) { - const trimmed = line.trim(); - if (!trimmed) continue; - sidecar.stderrTail.push(trimmed); - if (sidecar.stderrTail.length > 20) { - sidecar.stderrTail.shift(); - } - } - }); - - process.on('error', (error) => { - closeSidecar(sidecar, error instanceof Error ? error : new Error(String(error))); - }); - - process.on('close', (code, signal) => { - const stderrSummary = - sidecar.stderrTail.length > 0 ? ` stderr: ${sidecar.stderrTail.join(' | ')}` : ''; - closeSidecar( - sidecar, - new Error( - `Guile sidecar exited (code=${String(code)}, signal=${String(signal)}).${stderrSummary}`, - ), - ); - }); - - return sidecar; - } - - async function stopReplSidecar() { - if (!replSidecar) return; - - const sidecar = replSidecar; - replSidecar = undefined; - - if (sidecar.closedError) { - return; - } - - try { - sidecar.process.stdin.write('QUIT\n'); - } catch { - // ignore - } - - await new Promise((resolve) => { - const timer = setTimeout(() => { - if (!sidecar.process.killed) { - sidecar.process.kill('SIGTERM'); - } - }, 500); - - sidecar.process.once('close', () => { - clearTimeout(timer); - resolve(); - }); - }); - } - - async function ensureReplSidecar(cwd: string, signal?: AbortSignal): Promise { - if (replSidecar && !replSidecar.closedError && replSidecar.cwd !== cwd) { - await stopReplSidecar(); - } - - if (!replSidecar || replSidecar.closedError) { - const sidecar = createReplSidecar(cwd); - const ready = await waitForSidecarLine(sidecar, 5_000, signal); - if (ready !== 'READY') { - closeSidecar(sidecar, new Error(`Unexpected sidecar handshake: ${ready}`)); - throw new Error(`Failed to start pigibrack REPL sidecar: ${ready}`); - } - replSidecar = sidecar; - } - - return replSidecar; - } - - function sanitizeModuleSpec(moduleSpec: string | undefined): string { - if (!moduleSpec) return '-'; - return moduleSpec.replace(/[\t\n\r]/g, ' ').trim() || '-'; - } - - async function sidecarCommand( - cwd: string, - command: string, - signal?: AbortSignal, - ): Promise { - const sidecar = await ensureReplSidecar(cwd, signal); - - return enqueueSidecar(sidecar, async () => { - if (sidecar.closedError) throw sidecar.closedError; - - sidecar.process.stdin.write(`${command}\n`); - return await waitForSidecarLine(sidecar, 30_000, signal); - }); - } - - async function guileSyntaxCheck( - input: { path?: string; source?: string }, - signal?: AbortSignal, - ): Promise { - let targetPath: string | undefined; - - if (input.path) { - targetPath = input.path; - } else if (typeof input.source === 'string') { - targetPath = await writeTempScheme(input.source); - } - - if (!targetPath) { - return { valid: false, errors: ['Either path or source must be provided.'] }; - } - - const result = await pi.exec('guile', [CHECK_SYNTAX_SCRIPT, targetPath], { - signal, - timeout: 30_000, - }); - - if (result.code === 0) { - return { valid: true, errors: [] }; - } - - const message = - [result.stderr, result.stdout].filter(Boolean).join('\n').trim() || 'Unknown syntax error'; - return { valid: false, errors: [message] }; - } - - async function guileEvalDirect( - expr: string, - moduleSpec: string | undefined, - cwd: string, - signal?: AbortSignal, - ): Promise { - const exprPath = await writeTempScheme(expr); - const args = ['-L', cwd, EVAL_EXPR_SCRIPT, exprPath]; - if (moduleSpec) args.push(moduleSpec); - - const result = await pi.exec('guile', args, { - signal, - timeout: 30_000, - cwd, - }); - - if (result.code !== 0) { - const message = - [result.stderr, result.stdout].filter(Boolean).join('\n').trim() || - 'Guile evaluation failed.'; - throw new Error(message); - } - - return parseEvalOutput(result.stdout ?? ''); - } - - async function guileEval( - expr: string, - moduleSpec: string | undefined, - cwd: string, - signal?: AbortSignal, - ): Promise { - const dir = await mkdtemp(join(tmpdir(), 'pigibrack-repl-')); - const exprPath = join(dir, 'expr.scm'); - const stdoutPath = join(dir, 'stdout.txt'); - const valuePath = join(dir, 'value.txt'); - const errorPath = join(dir, 'error.txt'); - - await writeFile(exprPath, expr, 'utf8'); - - const command = [ - 'EVAL', - exprPath, - sanitizeModuleSpec(moduleSpec), - stdoutPath, - valuePath, - errorPath, - ].join('\t'); - - try { - const response = await sidecarCommand(cwd, command, signal); - const stdout = (await readFile(stdoutPath, 'utf8').catch(() => '')).trimEnd(); - const value = (await readFile(valuePath, 'utf8').catch(() => '')).trimEnd(); - const error = (await readFile(errorPath, 'utf8').catch(() => '')).trim(); - - if (response === 'DONE\tOK') { - return { stdout, value }; - } - - if (response === 'DONE\tERR') { - throw new Error(error || 'Guile sidecar evaluation failed.'); - } - - throw new Error(`Unexpected sidecar response: ${response}`); - } catch (error) { - // Fallback to non-persistent eval script so eval still works if sidecar is unavailable. - return await guileEvalDirect(expr, moduleSpec, cwd, signal); - } - } - - async function guileMacroExpand( - expr: string, - moduleSpec: string | undefined, - cwd: string, - signal?: AbortSignal, - ): Promise { - const dir = await mkdtemp(join(tmpdir(), 'pigibrack-mexp-')); - const exprPath = join(dir, 'expr.scm'); - const valuePath = join(dir, 'value.txt'); - const errorPath = join(dir, 'error.txt'); - - await writeFile(exprPath, expr, 'utf8'); - - const command = ['MEXP', exprPath, sanitizeModuleSpec(moduleSpec), valuePath, errorPath].join( - '\t', - ); - - try { - const response = await sidecarCommand(cwd, command, signal); - const value = (await readFile(valuePath, 'utf8').catch(() => '')).trimEnd(); - const error = (await readFile(errorPath, 'utf8').catch(() => '')).trim(); - - if (response === 'DONE\tOK') { - return value; - } - - if (response === 'DONE\tERR') { - throw new Error(error || 'Guile sidecar macro expansion failed.'); - } - - throw new Error(`Unexpected sidecar response: ${response}`); - } catch { - const fallbackExpr = `(begin (use-modules (language tree-il)) (tree-il->scheme (macroexpand ${expr})))`; - const result = await guileEvalDirect(fallbackExpr, moduleSpec, cwd, signal); - return result.value; - } - } - - pi.registerCommand('pigibrack-status', { - description: 'Show pigibrack extension status and guile availability', - handler: async (_args, ctx) => { - const scriptsExist = - existsSync(CHECK_SYNTAX_SCRIPT) && - existsSync(EVAL_EXPR_SCRIPT) && - existsSync(REPL_SIDECAR_SCRIPT); - const guileVersion = await pi.exec('guile', ['--version'], { timeout: 5_000 }); - - const lines = [ - `scripts: ${scriptsExist ? 'ok' : 'missing'}`, - `check_syntax.scm: ${CHECK_SYNTAX_SCRIPT}`, - `eval_expr.scm: ${EVAL_EXPR_SCRIPT}`, - `repl_sidecar.scm: ${REPL_SIDECAR_SCRIPT}`, - `guile available: ${guileVersion.code === 0 ? 'yes' : 'no'}`, - `sidecar running: ${replSidecar && !replSidecar.closedError ? 'yes' : 'no'}`, - ]; - - if (replSidecar && !replSidecar.closedError) { - lines.push(`sidecar cwd: ${replSidecar.cwd}`); - } - - if (guileVersion.code === 0) { - const firstLine = (guileVersion.stdout ?? '').split('\n')[0]?.trim(); - if (firstLine) lines.push(`guile: ${firstLine}`); - } - - ctx.ui.notify(lines.join('\n'), scriptsExist && guileVersion.code === 0 ? 'info' : 'warning'); - }, - }); - - pi.registerCommand('pigibrack-repl-reset', { - description: 'Reset the pigibrack persistent guile REPL sidecar', - handler: async (_args, ctx) => { - const response = await sidecarCommand(ctx.cwd, 'RESET'); - if (response !== 'DONE\tOK') { - throw new Error(`Unexpected sidecar response: ${response}`); - } - ctx.ui.notify('pigibrack REPL sidecar reset.', 'info'); - }, - }); - - pi.on('session_shutdown', async () => { - await stopReplSidecar(); - }); - - pi.registerTool({ - name: 'pigibrack_read_module', - label: 'pigibrack read module', - description: `Read a Scheme file as collapsed top-level forms (name + one-line summary). ${TOOL_DESCRIPTION_SUFFIX}`, - promptSnippet: 'Inspect Scheme modules by top-level forms before editing.', - promptGuidelines: [ - 'Use pigibrack_read_module before pigibrack_read_form for large Scheme files.', - ], - parameters: Type.Object({ - path: Type.String({ description: 'Path to a Scheme source file' }), - }), - async execute(_toolCallId, params, _signal, _onUpdate, ctx) { - const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); - const source = await readFile(absolutePath, 'utf8'); - const forms = parseTopLevelForms(source); - - const lines = forms.map((form, index) => { - const name = form.name ? ` name=${form.name}` : ''; - return `${String(index + 1).padStart(3, ' ')}. line ${form.line}${name} :: ${collapseForm(form.text)}`; - }); - - const output = `Module: ${params.path}\nTop-level forms: ${forms.length}\n\n${lines.join('\n')}`; - - return { - content: [{ type: 'text', text: formatTruncated(output, 'head') }], - details: { - path: params.path, - absolutePath, - forms: forms.length, - }, - }; - }, - }); - - pi.registerTool({ - name: 'pigibrack_read_form', - label: 'pigibrack read form', - description: `Read one top-level Scheme form by defined name. ${TOOL_DESCRIPTION_SUFFIX}`, - promptSnippet: 'Read an individual Scheme top-level form by name.', - promptGuidelines: ['Use pigibrack_read_form to fetch a form before replacing it.'], - parameters: Type.Object({ - path: Type.String({ description: 'Path to a Scheme source file' }), - name: Type.String({ description: 'Top-level form name (e.g. my-function)' }), - }), - async execute(_toolCallId, params, _signal, _onUpdate, ctx) { - const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); - const source = await readFile(absolutePath, 'utf8'); - const forms = parseTopLevelForms(source); - const form = uniqueByName(forms, params.name); - - return { - content: [{ type: 'text', text: formatTruncated(form.text, 'head') }], - details: { - path: params.path, - absolutePath, - name: params.name, - line: form.line, - }, - }; - }, - }); - - pi.registerTool({ - name: 'pigibrack_replace_form', - label: 'pigibrack replace form', - description: 'Replace a top-level Scheme form by name, with syntax pre-check via guile reader.', - promptSnippet: 'Replace an entire top-level Scheme form by name.', - promptGuidelines: [ - 'Always call pigibrack_read_form first, then replace with a complete new form.', - 'newSource must be exactly one top-level form.', - ], - parameters: Type.Object({ - path: Type.String({ description: 'Path to a Scheme source file' }), - name: Type.String({ description: 'Top-level form name to replace' }), - newSource: Type.String({ description: 'The complete new top-level form source' }), - }), - async execute(_toolCallId, params, signal, _onUpdate, ctx) { - const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); - const normalizedSource = ensureSingleTopLevelForm(params.newSource); - - const syntax = await guileSyntaxCheck({ source: normalizedSource }, signal); - if (!syntax.valid) { - throw new Error(`newSource is not valid Scheme: ${syntax.errors.join('; ')}`); - } - - return withFileMutationQueue(absolutePath, async () => { - const source = await readFile(absolutePath, 'utf8'); - const forms = parseTopLevelForms(source); - const form = uniqueByName(forms, params.name); - - const updated = `${source.slice(0, form.start)}${normalizedSource}${source.slice(form.end)}`; - await writeFile(absolutePath, updated, 'utf8'); - - return { - content: [ - { - type: 'text', - text: `Replaced form "${params.name}" at line ${form.line} in ${params.path}.`, - }, - ], - details: { - path: params.path, - absolutePath, - name: params.name, - line: form.line, - }, - }; - }); - }, - }); - - pi.registerTool({ - name: 'pigibrack_insert_form', - label: 'pigibrack insert form', - description: 'Insert a new top-level Scheme form before or after an anchor form by name.', - promptSnippet: 'Insert a new top-level Scheme form relative to an existing named form.', - parameters: Type.Object({ - path: Type.String({ description: 'Path to a Scheme source file' }), - anchorName: Type.String({ description: 'Anchor form name for insertion' }), - position: StringEnum(['before', 'after'] as const), - newSource: Type.String({ description: 'New top-level form source' }), - }), - async execute(_toolCallId, params, signal, _onUpdate, ctx) { - const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); - const normalizedSource = ensureSingleTopLevelForm(params.newSource); - - const syntax = await guileSyntaxCheck({ source: normalizedSource }, signal); - if (!syntax.valid) { - throw new Error(`newSource is not valid Scheme: ${syntax.errors.join('; ')}`); - } - - return withFileMutationQueue(absolutePath, async () => { - const source = await readFile(absolutePath, 'utf8'); - const forms = parseTopLevelForms(source); - const anchor = uniqueByName(forms, params.anchorName); - - const insertionPoint = params.position === 'before' ? anchor.start : anchor.end; - - const left = source.slice(0, insertionPoint); - const right = source.slice(insertionPoint); - - const needsLeadingNewline = left.length > 0 && !left.endsWith('\n'); - const needsTrailingNewline = right.length > 0 && !right.startsWith('\n'); - - const inserted = `${needsLeadingNewline ? '\n' : ''}${normalizedSource}${needsTrailingNewline ? '\n' : ''}`; - const updated = `${left}${inserted}${right}`; - - await writeFile(absolutePath, updated, 'utf8'); - - return { - content: [ - { - type: 'text', - text: `Inserted form ${params.position} "${params.anchorName}" (line ${anchor.line}) in ${params.path}.`, - }, - ], - details: { - path: params.path, - absolutePath, - anchorName: params.anchorName, - position: params.position, - line: anchor.line, - }, - }; - }); - }, - }); - - pi.registerTool({ - name: 'pigibrack_delete_form', - label: 'pigibrack delete form', - description: 'Delete a top-level Scheme form by name.', - promptSnippet: 'Delete a top-level Scheme form by its name.', - parameters: Type.Object({ - path: Type.String({ description: 'Path to a Scheme source file' }), - name: Type.String({ description: 'Top-level form name to delete' }), - }), - async execute(_toolCallId, params, _signal, _onUpdate, ctx) { - const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); - - return withFileMutationQueue(absolutePath, async () => { - const source = await readFile(absolutePath, 'utf8'); - const forms = parseTopLevelForms(source); - const form = uniqueByName(forms, params.name); - - let start = form.start; - let end = form.end; - - if (source[end] === '\n') end += 1; - if (start > 0 && source[start - 1] === '\n' && source[end] === '\n') start -= 1; - - const updated = `${source.slice(0, start)}${source.slice(end)}`; - await writeFile(absolutePath, updated, 'utf8'); - - return { - content: [{ type: 'text', text: `Deleted form "${params.name}" from ${params.path}.` }], - details: { - path: params.path, - absolutePath, - name: params.name, - line: form.line, - }, - }; - }); - }, - }); - - pi.registerTool({ - name: 'pigibrack_check_syntax', - label: 'pigibrack check syntax', - description: - 'Check Scheme syntax via guile reader. Accepts either a file path or inline source.', - promptSnippet: 'Validate Scheme syntax before editing or evaluating.', - parameters: Type.Object({ - path: Type.Optional(Type.String({ description: 'Path to a Scheme source file' })), - source: Type.Optional(Type.String({ description: 'Inline Scheme source to validate' })), - }), - async execute(_toolCallId, params, signal, _onUpdate, ctx) { - if (!params.path && typeof params.source !== 'string') { - throw new Error('Provide either path or source.'); - } - - if (params.path && typeof params.source === 'string') { - throw new Error('Provide path or source, not both.'); - } - - const resolvedPath = params.path - ? resolve(ctx.cwd, normalizeUserPath(params.path)) - : undefined; - const result = await guileSyntaxCheck({ path: resolvedPath, source: params.source }, signal); - - const output = result.valid - ? 'Syntax check: valid ✅' - : `Syntax check: invalid ❌\n\n${result.errors.map((error, index) => `${index + 1}. ${error}`).join('\n')}`; - - return { - content: [{ type: 'text', text: formatTruncated(output, 'head') }], - details: { - valid: result.valid, - errors: result.errors, - path: params.path, - }, - }; - }, - }); - - pi.registerTool({ - name: 'pigibrack_macro_expand', - label: 'pigibrack macro expand', - description: - 'Macro-expand a Scheme expression in guile. Optional module is a module spec, e.g. (my module).', - promptSnippet: - 'Expand a Scheme form to inspect macro output before debugging runtime behavior.', - parameters: Type.Object({ - expr: Type.String({ description: 'A Scheme expression to macro-expand' }), - module: Type.Optional(Type.String({ description: 'Optional module spec, e.g. (my module)' })), - }), - async execute(_toolCallId, params, signal, _onUpdate, ctx) { - const normalizedExpr = ensureSingleTopLevelForm(params.expr); - const expanded = await guileMacroExpand(normalizedExpr, params.module, ctx.cwd, signal); - - const output = `expanded:\n${expanded || ''}`; - - return { - content: [{ type: 'text', text: formatTruncated(output, 'tail') }], - details: { - module: params.module, - }, - }; - }, - }); - - pi.registerTool({ - name: 'pigibrack_eval_expr', - label: 'pigibrack eval expr', - description: `Evaluate a Scheme expression in guile. Optional module is a module spec, e.g. (my module). ${TOOL_DESCRIPTION_SUFFIX}`, - promptSnippet: 'Evaluate Scheme expressions in guile for fast feedback.', - promptGuidelines: [ - 'Use pigibrack_eval_expr after structural edits to validate behavior quickly.', - ], - parameters: Type.Object({ - expr: Type.String({ description: 'A Scheme expression to evaluate' }), - module: Type.Optional(Type.String({ description: 'Optional module spec, e.g. (my module)' })), - }), - async execute(_toolCallId, params, signal, _onUpdate, ctx) { - const result = await guileEval(params.expr, params.module, ctx.cwd, signal); - - const outputParts = [] as string[]; - if (result.stdout.trim()) { - outputParts.push(`stdout:\n${result.stdout}`); - } - outputParts.push(`result:\n${result.value || ''}`); - - return { - content: [{ type: 'text', text: formatTruncated(outputParts.join('\n\n'), 'tail') }], - details: { - module: params.module, - hasStdout: result.stdout.trim().length > 0, - }, - }; - }, - }); -} +export { default } from '../../../extensions/pigibrack/index.ts'; diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1d87c16 --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2026, pigibrack contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..5c07f89 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# pigibrack + +Pi package providing a Guile/Scheme structural editing extension. + +## Features + +- Top-level form tools by name: + - `pigibrack_read_module` + - `pigibrack_read_form` + - `pigibrack_replace_form` + - `pigibrack_insert_form` + - `pigibrack_delete_form` +- Syntax checks via Guile reader: `pigibrack_check_syntax` +- Persistent Guile REPL sidecar eval: `pigibrack_eval_expr` +- Macro expansion: `pigibrack_macro_expand` +- Commands: + - `/pigibrack-status` + - `/pigibrack-repl-reset` + +## Install in pi + +```bash +pi install npm:pigibrack +``` + +Or project-local: + +```bash +pi install -l npm:pigibrack +``` + +## Manual load (this repo) + +Pi auto-discovers `.pi/extensions/pigibrack/index.ts` in this repository. + +## Package manifest + +This package declares: + +```json +{ + "pi": { + "extensions": ["./extensions/pigibrack/index.ts"] + } +} +``` + +## License + +BSD-2-Clause. diff --git a/.pi/extensions/pigibrack/README.md b/extensions/pigibrack/README.md similarity index 87% rename from .pi/extensions/pigibrack/README.md rename to extensions/pigibrack/README.md index e671ebf..decf414 100644 --- a/.pi/extensions/pigibrack/README.md +++ b/extensions/pigibrack/README.md @@ -22,16 +22,14 @@ Commands: ## How to load -This extension is project-local at: +As a package resource, this extension entrypoint is: + +- `extensions/pigibrack/index.ts` + +When developing in this repository, Pi auto-discovers the shim at: - `.pi/extensions/pigibrack/index.ts` -Pi auto-discovers this path. You can also start explicitly: - -```bash -pi -e ./.pi/extensions/pigibrack/index.ts -``` - ## Notes - Structural operations are top-level form by **name**. diff --git a/.pi/extensions/pigibrack/guile/check_syntax.scm b/extensions/pigibrack/guile/check_syntax.scm similarity index 100% rename from .pi/extensions/pigibrack/guile/check_syntax.scm rename to extensions/pigibrack/guile/check_syntax.scm diff --git a/.pi/extensions/pigibrack/guile/eval_expr.scm b/extensions/pigibrack/guile/eval_expr.scm similarity index 100% rename from .pi/extensions/pigibrack/guile/eval_expr.scm rename to extensions/pigibrack/guile/eval_expr.scm diff --git a/.pi/extensions/pigibrack/guile/repl_sidecar.scm b/extensions/pigibrack/guile/repl_sidecar.scm similarity index 100% rename from .pi/extensions/pigibrack/guile/repl_sidecar.scm rename to extensions/pigibrack/guile/repl_sidecar.scm diff --git a/extensions/pigibrack/index.ts b/extensions/pigibrack/index.ts new file mode 100644 index 0000000..cf67922 --- /dev/null +++ b/extensions/pigibrack/index.ts @@ -0,0 +1,1076 @@ +import { StringEnum, Type } from '@mariozechner/pi-ai'; +import { + DEFAULT_MAX_BYTES, + DEFAULT_MAX_LINES, + formatSize, + truncateHead, + truncateTail, + withFileMutationQueue, + type ExtensionAPI, +} from '@mariozechner/pi-coding-agent'; +import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'; +import { existsSync } from 'node:fs'; +import { mkdtemp, readFile, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { createInterface } from 'node:readline'; + +const CHECK_SYNTAX_SCRIPT = resolve(__dirname, 'guile/check_syntax.scm'); +const EVAL_EXPR_SCRIPT = resolve(__dirname, 'guile/eval_expr.scm'); +const REPL_SIDECAR_SCRIPT = resolve(__dirname, 'guile/repl_sidecar.scm'); + +const TOOL_DESCRIPTION_SUFFIX = `Tool output is truncated to ${DEFAULT_MAX_LINES} lines or ${formatSize(DEFAULT_MAX_BYTES)}.`; + +interface FormSpan { + start: number; + end: number; + line: number; + text: string; + name?: string; +} + +interface SyntaxCheckResult { + valid: boolean; + errors: string[]; +} + +interface EvalResult { + stdout: string; + value: string; +} + +interface SidecarWaiter { + resolve: (line: string) => void; + reject: (error: Error) => void; +} + +interface ReplSidecar { + process: ChildProcessWithoutNullStreams; + cwd: string; + lines: string[]; + waiters: SidecarWaiter[]; + queue: Promise; + stderrTail: string[]; + closedError?: Error; +} + +function normalizeUserPath(path: string): string { + return path.startsWith('@') ? path.slice(1) : path; +} + +function lineNumberAt(source: string, index: number): number { + let line = 1; + for (let i = 0; i < index && i < source.length; i += 1) { + if (source[i] === '\n') line += 1; + } + return line; +} + +function isWhitespace(ch: string | undefined): boolean { + return ch === ' ' || ch === '\n' || ch === '\r' || ch === '\t' || ch === '\f'; +} + +function isDelimiter(ch: string | undefined): boolean { + if (ch === undefined) return true; + return ( + isWhitespace(ch) || + ch === '(' || + ch === ')' || + ch === '[' || + ch === ']' || + ch === '"' || + ch === ';' + ); +} + +function parseTopLevelForms(source: string): FormSpan[] { + const len = source.length; + + function skipLineComment(i: number): number { + let cursor = i; + while (cursor < len && source[cursor] !== '\n') cursor += 1; + return cursor; + } + + function skipBlockComment(i: number): number { + let cursor = i + 2; + let depth = 1; + + while (cursor < len - 1) { + if (source[cursor] === '#' && source[cursor + 1] === '|') { + depth += 1; + cursor += 2; + continue; + } + if (source[cursor] === '|' && source[cursor + 1] === '#') { + depth -= 1; + cursor += 2; + if (depth === 0) return cursor; + continue; + } + cursor += 1; + } + + throw new Error('Unterminated block comment (#| ... |#).'); + } + + function parseString(i: number): number { + let cursor = i + 1; + let escaped = false; + + while (cursor < len) { + const ch = source[cursor]; + if (escaped) { + escaped = false; + } else if (ch === '\\') { + escaped = true; + } else if (ch === '"') { + return cursor + 1; + } + cursor += 1; + } + + throw new Error('Unterminated string literal.'); + } + + function parseAtom(i: number): number { + let cursor = i; + + while (cursor < len) { + const ch = source[cursor]; + if (isDelimiter(ch)) break; + if (ch === '#' && (source[cursor + 1] === '|' || source[cursor + 1] === ';')) break; + cursor += 1; + } + + if (cursor === i) throw new Error(`Unexpected token at index ${i}.`); + return cursor; + } + + function skipTrivia(i: number): number { + let cursor = i; + + while (cursor < len) { + const ch = source[cursor]; + + if (isWhitespace(ch)) { + cursor += 1; + continue; + } + + if (ch === ';') { + cursor = skipLineComment(cursor); + continue; + } + + if (ch === '#' && source[cursor + 1] === '|') { + cursor = skipBlockComment(cursor); + continue; + } + + if (ch === '#' && source[cursor + 1] === ';') { + cursor += 2; + cursor = skipTrivia(cursor); + cursor = parseDatum(cursor); + continue; + } + + break; + } + + return cursor; + } + + function parseList(i: number): number { + const open = source[i]; + const close = open === '(' ? ')' : ']'; + let cursor = i + 1; + + while (cursor < len) { + cursor = skipTrivia(cursor); + if (cursor >= len) break; + + if (source[cursor] === close) return cursor + 1; + if (source[cursor] === ')' || source[cursor] === ']') { + throw new Error(`Mismatched list delimiter near index ${cursor}.`); + } + + cursor = parseDatum(cursor); + } + + throw new Error('Unterminated list form.'); + } + + function parseDatum(i: number): number { + const cursor = skipTrivia(i); + if (cursor >= len) throw new Error('Unexpected end of input.'); + + const ch = source[cursor]; + + if (ch === '(' || ch === '[') { + return parseList(cursor); + } + + if (ch === '"') { + return parseString(cursor); + } + + if (ch === "'" || ch === '`') { + return parseDatum(cursor + 1); + } + + if (ch === ',') { + return parseDatum(source[cursor + 1] === '@' ? cursor + 2 : cursor + 1); + } + + if (ch === '#') { + if (source[cursor + 1] === '(' || source[cursor + 1] === '[') { + return parseList(cursor + 1); + } + + let maybeVectorCursor = cursor + 1; + while (/[a-zA-Z0-9]/.test(source[maybeVectorCursor] ?? '')) maybeVectorCursor += 1; + if (source[maybeVectorCursor] === '(' || source[maybeVectorCursor] === '[') { + return parseList(maybeVectorCursor); + } + } + + return parseAtom(cursor); + } + + const forms: FormSpan[] = []; + let cursor = skipTrivia(0); + + while (cursor < len) { + const start = cursor; + const end = parseDatum(cursor); + const text = source.slice(start, end); + + forms.push({ + start, + end, + line: lineNumberAt(source, start), + text, + name: extractFormName(text), + }); + + cursor = skipTrivia(end); + } + + return forms; +} + +function extractFormName(formText: string): string | undefined { + const trimmed = formText.trim(); + if (!trimmed.startsWith('(')) return undefined; + + const patterns = [ + /^\(\s*(?:define|define-public|define\*)\s+\(([^\s()\[\]]+)/, + /^\(\s*(?:define|define-public|define\*)\s+([^\s()\[\]]+)/, + /^\(\s*(?:define-syntax|define-syntax-rule|define-macro)\s+\(([^\s()\[\]]+)/, + /^\(\s*(?:define-syntax|define-syntax-rule|define-macro)\s+([^\s()\[\]]+)/, + /^\(\s*define-record-type\s+([^\s()\[\]]+)/, + /^\(\s*define-class\s+([^\s()\[\]]+)/, + ]; + + for (const pattern of patterns) { + const match = trimmed.match(pattern); + if (match?.[1]) return match[1]; + } + + return undefined; +} + +function oneLine(text: string): string { + return text.replace(/\s+/g, ' ').trim(); +} + +function collapseForm(formText: string): string { + const trimmed = formText.trim(); + const lines = trimmed.split('\n'); + + let output = lines.length <= 5 ? oneLine(trimmed) : `${oneLine(lines[0] ?? trimmed)} ...`; + + if (output.length > 160) { + output = `${output.slice(0, 157)}...`; + } + + return output; +} + +function uniqueByName(forms: FormSpan[], name: string): FormSpan { + const matches = forms.filter((form) => form.name === name); + + if (matches.length === 0) { + const available = Array.from(new Set(forms.map((form) => form.name).filter(Boolean))).slice( + 0, + 30, + ) as string[]; + const suffix = available.length > 0 ? ` Available names: ${available.join(', ')}` : ''; + throw new Error(`No top-level form named "${name}" found.${suffix}`); + } + + if (matches.length > 1) { + const locations = matches.map((match) => `line ${match.line}`).join(', '); + throw new Error( + `Multiple forms named "${name}" found (${locations}). Please disambiguate first.`, + ); + } + + return matches[0]; +} + +function ensureSingleTopLevelForm(source: string): string { + const trimmed = source.trim(); + if (!trimmed) throw new Error('newSource is empty.'); + + const forms = parseTopLevelForms(trimmed); + if (forms.length !== 1 || forms[0].start !== 0 || forms[0].end !== trimmed.length) { + throw new Error('newSource must contain exactly one top-level form.'); + } + + return trimmed; +} + +function formatTruncated(text: string, mode: 'head' | 'tail' = 'head'): string { + const truncation = + mode === 'head' + ? truncateHead(text, { maxLines: DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES }) + : truncateTail(text, { maxLines: DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES }); + + let output = truncation.content; + if (truncation.truncated) { + output += `\n\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines, ${formatSize(truncation.outputBytes)}/${formatSize(truncation.totalBytes)}.]`; + } + + return output; +} + +function parseEvalOutput(raw: string): EvalResult { + const stdoutStart = '__PIGI_STDOUT_START__\n'; + const stdoutEnd = '__PIGI_STDOUT_END__\n'; + const resultStart = '__PIGI_RESULT_START__\n'; + const resultEnd = '__PIGI_RESULT_END__\n'; + + const stdoutStartIndex = raw.indexOf(stdoutStart); + const stdoutEndIndex = raw.indexOf(stdoutEnd); + const resultStartIndex = raw.indexOf(resultStart); + const resultEndIndex = raw.indexOf(resultEnd); + + if ( + stdoutStartIndex === -1 || + stdoutEndIndex === -1 || + resultStartIndex === -1 || + resultEndIndex === -1 + ) { + return { stdout: '', value: raw.trim() }; + } + + const stdout = raw.slice(stdoutStartIndex + stdoutStart.length, stdoutEndIndex); + const value = raw.slice(resultStartIndex + resultStart.length, resultEndIndex); + + return { stdout: stdout.trimEnd(), value: value.trimEnd() }; +} + +async function writeTempScheme(source: string): Promise { + const dir = await mkdtemp(join(tmpdir(), 'pigibrack-')); + const file = join(dir, 'input.scm'); + await writeFile(file, source, 'utf8'); + return file; +} + +export default function pigibrackExtension(pi: ExtensionAPI) { + let replSidecar: ReplSidecar | undefined; + + function closeSidecar(sidecar: ReplSidecar, error: Error) { + if (sidecar.closedError) return; + + sidecar.closedError = error; + for (const waiter of sidecar.waiters) { + waiter.reject(error); + } + sidecar.waiters = []; + + if (replSidecar === sidecar) { + replSidecar = undefined; + } + } + + function readSidecarLine(sidecar: ReplSidecar): Promise { + if (sidecar.lines.length > 0) { + return Promise.resolve(sidecar.lines.shift() as string); + } + + if (sidecar.closedError) { + return Promise.reject(sidecar.closedError); + } + + return new Promise((resolve, reject) => { + sidecar.waiters.push({ resolve, reject }); + }); + } + + async function waitForSidecarLine( + sidecar: ReplSidecar, + timeoutMs: number, + signal?: AbortSignal, + ): Promise { + const linePromise = readSidecarLine(sidecar); + + return await new Promise((resolve, reject) => { + let done = false; + + const finish = (fn: () => void) => { + if (done) return; + done = true; + clearTimeout(timeout); + if (signal) { + signal.removeEventListener('abort', onAbort); + } + fn(); + }; + + const timeout = setTimeout(() => { + finish(() => + reject(new Error(`Timed out waiting for sidecar response after ${timeoutMs}ms.`)), + ); + }, timeoutMs); + + const onAbort = () => { + finish(() => reject(new Error('Operation cancelled.'))); + }; + + if (signal) { + if (signal.aborted) { + finish(() => reject(new Error('Operation cancelled.'))); + return; + } + signal.addEventListener('abort', onAbort, { once: true }); + } + + linePromise.then( + (line) => finish(() => resolve(line)), + (error) => finish(() => reject(error)), + ); + }); + } + + function enqueueSidecar(sidecar: ReplSidecar, task: () => Promise): Promise { + const run = sidecar.queue.then(task, task); + sidecar.queue = run.then( + () => undefined, + () => undefined, + ); + return run; + } + + function createReplSidecar(cwd: string): ReplSidecar { + const process = spawn('guile', ['-L', cwd, REPL_SIDECAR_SCRIPT], { + cwd, + stdio: ['pipe', 'pipe', 'pipe'], + }); + + const sidecar: ReplSidecar = { + process, + cwd, + lines: [], + waiters: [], + queue: Promise.resolve(), + stderrTail: [], + }; + + const stdoutReader = createInterface({ input: process.stdout }); + stdoutReader.on('line', (line) => { + if (sidecar.waiters.length > 0) { + const waiter = sidecar.waiters.shift() as SidecarWaiter; + waiter.resolve(line); + } else { + sidecar.lines.push(line); + } + }); + + process.stderr.on('data', (chunk) => { + const text = String(chunk); + for (const line of text.split('\n')) { + const trimmed = line.trim(); + if (!trimmed) continue; + sidecar.stderrTail.push(trimmed); + if (sidecar.stderrTail.length > 20) { + sidecar.stderrTail.shift(); + } + } + }); + + process.on('error', (error) => { + closeSidecar(sidecar, error instanceof Error ? error : new Error(String(error))); + }); + + process.on('close', (code, signal) => { + const stderrSummary = + sidecar.stderrTail.length > 0 ? ` stderr: ${sidecar.stderrTail.join(' | ')}` : ''; + closeSidecar( + sidecar, + new Error( + `Guile sidecar exited (code=${String(code)}, signal=${String(signal)}).${stderrSummary}`, + ), + ); + }); + + return sidecar; + } + + async function stopReplSidecar() { + if (!replSidecar) return; + + const sidecar = replSidecar; + replSidecar = undefined; + + if (sidecar.closedError) { + return; + } + + try { + sidecar.process.stdin.write('QUIT\n'); + } catch { + // ignore + } + + await new Promise((resolve) => { + const timer = setTimeout(() => { + if (!sidecar.process.killed) { + sidecar.process.kill('SIGTERM'); + } + }, 500); + + sidecar.process.once('close', () => { + clearTimeout(timer); + resolve(); + }); + }); + } + + async function ensureReplSidecar(cwd: string, signal?: AbortSignal): Promise { + if (replSidecar && !replSidecar.closedError && replSidecar.cwd !== cwd) { + await stopReplSidecar(); + } + + if (!replSidecar || replSidecar.closedError) { + const sidecar = createReplSidecar(cwd); + const ready = await waitForSidecarLine(sidecar, 5_000, signal); + if (ready !== 'READY') { + closeSidecar(sidecar, new Error(`Unexpected sidecar handshake: ${ready}`)); + throw new Error(`Failed to start pigibrack REPL sidecar: ${ready}`); + } + replSidecar = sidecar; + } + + return replSidecar; + } + + function sanitizeModuleSpec(moduleSpec: string | undefined): string { + if (!moduleSpec) return '-'; + return moduleSpec.replace(/[\t\n\r]/g, ' ').trim() || '-'; + } + + async function sidecarCommand( + cwd: string, + command: string, + signal?: AbortSignal, + ): Promise { + const sidecar = await ensureReplSidecar(cwd, signal); + + return enqueueSidecar(sidecar, async () => { + if (sidecar.closedError) throw sidecar.closedError; + + sidecar.process.stdin.write(`${command}\n`); + return await waitForSidecarLine(sidecar, 30_000, signal); + }); + } + + async function guileSyntaxCheck( + input: { path?: string; source?: string }, + signal?: AbortSignal, + ): Promise { + let targetPath: string | undefined; + + if (input.path) { + targetPath = input.path; + } else if (typeof input.source === 'string') { + targetPath = await writeTempScheme(input.source); + } + + if (!targetPath) { + return { valid: false, errors: ['Either path or source must be provided.'] }; + } + + const result = await pi.exec('guile', [CHECK_SYNTAX_SCRIPT, targetPath], { + signal, + timeout: 30_000, + }); + + if (result.code === 0) { + return { valid: true, errors: [] }; + } + + const message = + [result.stderr, result.stdout].filter(Boolean).join('\n').trim() || 'Unknown syntax error'; + return { valid: false, errors: [message] }; + } + + async function guileEvalDirect( + expr: string, + moduleSpec: string | undefined, + cwd: string, + signal?: AbortSignal, + ): Promise { + const exprPath = await writeTempScheme(expr); + const args = ['-L', cwd, EVAL_EXPR_SCRIPT, exprPath]; + if (moduleSpec) args.push(moduleSpec); + + const result = await pi.exec('guile', args, { + signal, + timeout: 30_000, + cwd, + }); + + if (result.code !== 0) { + const message = + [result.stderr, result.stdout].filter(Boolean).join('\n').trim() || + 'Guile evaluation failed.'; + throw new Error(message); + } + + return parseEvalOutput(result.stdout ?? ''); + } + + async function guileEval( + expr: string, + moduleSpec: string | undefined, + cwd: string, + signal?: AbortSignal, + ): Promise { + const dir = await mkdtemp(join(tmpdir(), 'pigibrack-repl-')); + const exprPath = join(dir, 'expr.scm'); + const stdoutPath = join(dir, 'stdout.txt'); + const valuePath = join(dir, 'value.txt'); + const errorPath = join(dir, 'error.txt'); + + await writeFile(exprPath, expr, 'utf8'); + + const command = [ + 'EVAL', + exprPath, + sanitizeModuleSpec(moduleSpec), + stdoutPath, + valuePath, + errorPath, + ].join('\t'); + + try { + const response = await sidecarCommand(cwd, command, signal); + const stdout = (await readFile(stdoutPath, 'utf8').catch(() => '')).trimEnd(); + const value = (await readFile(valuePath, 'utf8').catch(() => '')).trimEnd(); + const error = (await readFile(errorPath, 'utf8').catch(() => '')).trim(); + + if (response === 'DONE\tOK') { + return { stdout, value }; + } + + if (response === 'DONE\tERR') { + throw new Error(error || 'Guile sidecar evaluation failed.'); + } + + throw new Error(`Unexpected sidecar response: ${response}`); + } catch (error) { + // Fallback to non-persistent eval script so eval still works if sidecar is unavailable. + return await guileEvalDirect(expr, moduleSpec, cwd, signal); + } + } + + async function guileMacroExpand( + expr: string, + moduleSpec: string | undefined, + cwd: string, + signal?: AbortSignal, + ): Promise { + const dir = await mkdtemp(join(tmpdir(), 'pigibrack-mexp-')); + const exprPath = join(dir, 'expr.scm'); + const valuePath = join(dir, 'value.txt'); + const errorPath = join(dir, 'error.txt'); + + await writeFile(exprPath, expr, 'utf8'); + + const command = ['MEXP', exprPath, sanitizeModuleSpec(moduleSpec), valuePath, errorPath].join( + '\t', + ); + + try { + const response = await sidecarCommand(cwd, command, signal); + const value = (await readFile(valuePath, 'utf8').catch(() => '')).trimEnd(); + const error = (await readFile(errorPath, 'utf8').catch(() => '')).trim(); + + if (response === 'DONE\tOK') { + return value; + } + + if (response === 'DONE\tERR') { + throw new Error(error || 'Guile sidecar macro expansion failed.'); + } + + throw new Error(`Unexpected sidecar response: ${response}`); + } catch { + const fallbackExpr = `(begin (use-modules (language tree-il)) (tree-il->scheme (macroexpand ${expr})))`; + const result = await guileEvalDirect(fallbackExpr, moduleSpec, cwd, signal); + return result.value; + } + } + + pi.registerCommand('pigibrack-status', { + description: 'Show pigibrack extension status and guile availability', + handler: async (_args, ctx) => { + const scriptsExist = + existsSync(CHECK_SYNTAX_SCRIPT) && + existsSync(EVAL_EXPR_SCRIPT) && + existsSync(REPL_SIDECAR_SCRIPT); + const guileVersion = await pi.exec('guile', ['--version'], { timeout: 5_000 }); + + const lines = [ + `scripts: ${scriptsExist ? 'ok' : 'missing'}`, + `check_syntax.scm: ${CHECK_SYNTAX_SCRIPT}`, + `eval_expr.scm: ${EVAL_EXPR_SCRIPT}`, + `repl_sidecar.scm: ${REPL_SIDECAR_SCRIPT}`, + `guile available: ${guileVersion.code === 0 ? 'yes' : 'no'}`, + `sidecar running: ${replSidecar && !replSidecar.closedError ? 'yes' : 'no'}`, + ]; + + if (replSidecar && !replSidecar.closedError) { + lines.push(`sidecar cwd: ${replSidecar.cwd}`); + } + + if (guileVersion.code === 0) { + const firstLine = (guileVersion.stdout ?? '').split('\n')[0]?.trim(); + if (firstLine) lines.push(`guile: ${firstLine}`); + } + + ctx.ui.notify(lines.join('\n'), scriptsExist && guileVersion.code === 0 ? 'info' : 'warning'); + }, + }); + + pi.registerCommand('pigibrack-repl-reset', { + description: 'Reset the pigibrack persistent guile REPL sidecar', + handler: async (_args, ctx) => { + const response = await sidecarCommand(ctx.cwd, 'RESET'); + if (response !== 'DONE\tOK') { + throw new Error(`Unexpected sidecar response: ${response}`); + } + ctx.ui.notify('pigibrack REPL sidecar reset.', 'info'); + }, + }); + + pi.on('session_shutdown', async () => { + await stopReplSidecar(); + }); + + pi.registerTool({ + name: 'pigibrack_read_module', + label: 'pigibrack read module', + description: `Read a Scheme file as collapsed top-level forms (name + one-line summary). ${TOOL_DESCRIPTION_SUFFIX}`, + promptSnippet: 'Inspect Scheme modules by top-level forms before editing.', + promptGuidelines: [ + 'Use pigibrack_read_module before pigibrack_read_form for large Scheme files.', + ], + parameters: Type.Object({ + path: Type.String({ description: 'Path to a Scheme source file' }), + }), + async execute(_toolCallId, params, _signal, _onUpdate, ctx) { + const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); + const source = await readFile(absolutePath, 'utf8'); + const forms = parseTopLevelForms(source); + + const lines = forms.map((form, index) => { + const name = form.name ? ` name=${form.name}` : ''; + return `${String(index + 1).padStart(3, ' ')}. line ${form.line}${name} :: ${collapseForm(form.text)}`; + }); + + const output = `Module: ${params.path}\nTop-level forms: ${forms.length}\n\n${lines.join('\n')}`; + + return { + content: [{ type: 'text', text: formatTruncated(output, 'head') }], + details: { + path: params.path, + absolutePath, + forms: forms.length, + }, + }; + }, + }); + + pi.registerTool({ + name: 'pigibrack_read_form', + label: 'pigibrack read form', + description: `Read one top-level Scheme form by defined name. ${TOOL_DESCRIPTION_SUFFIX}`, + promptSnippet: 'Read an individual Scheme top-level form by name.', + promptGuidelines: ['Use pigibrack_read_form to fetch a form before replacing it.'], + parameters: Type.Object({ + path: Type.String({ description: 'Path to a Scheme source file' }), + name: Type.String({ description: 'Top-level form name (e.g. my-function)' }), + }), + async execute(_toolCallId, params, _signal, _onUpdate, ctx) { + const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); + const source = await readFile(absolutePath, 'utf8'); + const forms = parseTopLevelForms(source); + const form = uniqueByName(forms, params.name); + + return { + content: [{ type: 'text', text: formatTruncated(form.text, 'head') }], + details: { + path: params.path, + absolutePath, + name: params.name, + line: form.line, + }, + }; + }, + }); + + pi.registerTool({ + name: 'pigibrack_replace_form', + label: 'pigibrack replace form', + description: 'Replace a top-level Scheme form by name, with syntax pre-check via guile reader.', + promptSnippet: 'Replace an entire top-level Scheme form by name.', + promptGuidelines: [ + 'Always call pigibrack_read_form first, then replace with a complete new form.', + 'newSource must be exactly one top-level form.', + ], + parameters: Type.Object({ + path: Type.String({ description: 'Path to a Scheme source file' }), + name: Type.String({ description: 'Top-level form name to replace' }), + newSource: Type.String({ description: 'The complete new top-level form source' }), + }), + async execute(_toolCallId, params, signal, _onUpdate, ctx) { + const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); + const normalizedSource = ensureSingleTopLevelForm(params.newSource); + + const syntax = await guileSyntaxCheck({ source: normalizedSource }, signal); + if (!syntax.valid) { + throw new Error(`newSource is not valid Scheme: ${syntax.errors.join('; ')}`); + } + + return withFileMutationQueue(absolutePath, async () => { + const source = await readFile(absolutePath, 'utf8'); + const forms = parseTopLevelForms(source); + const form = uniqueByName(forms, params.name); + + const updated = `${source.slice(0, form.start)}${normalizedSource}${source.slice(form.end)}`; + await writeFile(absolutePath, updated, 'utf8'); + + return { + content: [ + { + type: 'text', + text: `Replaced form "${params.name}" at line ${form.line} in ${params.path}.`, + }, + ], + details: { + path: params.path, + absolutePath, + name: params.name, + line: form.line, + }, + }; + }); + }, + }); + + pi.registerTool({ + name: 'pigibrack_insert_form', + label: 'pigibrack insert form', + description: 'Insert a new top-level Scheme form before or after an anchor form by name.', + promptSnippet: 'Insert a new top-level Scheme form relative to an existing named form.', + parameters: Type.Object({ + path: Type.String({ description: 'Path to a Scheme source file' }), + anchorName: Type.String({ description: 'Anchor form name for insertion' }), + position: StringEnum(['before', 'after'] as const), + newSource: Type.String({ description: 'New top-level form source' }), + }), + async execute(_toolCallId, params, signal, _onUpdate, ctx) { + const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); + const normalizedSource = ensureSingleTopLevelForm(params.newSource); + + const syntax = await guileSyntaxCheck({ source: normalizedSource }, signal); + if (!syntax.valid) { + throw new Error(`newSource is not valid Scheme: ${syntax.errors.join('; ')}`); + } + + return withFileMutationQueue(absolutePath, async () => { + const source = await readFile(absolutePath, 'utf8'); + const forms = parseTopLevelForms(source); + const anchor = uniqueByName(forms, params.anchorName); + + const insertionPoint = params.position === 'before' ? anchor.start : anchor.end; + + const left = source.slice(0, insertionPoint); + const right = source.slice(insertionPoint); + + const needsLeadingNewline = left.length > 0 && !left.endsWith('\n'); + const needsTrailingNewline = right.length > 0 && !right.startsWith('\n'); + + const inserted = `${needsLeadingNewline ? '\n' : ''}${normalizedSource}${needsTrailingNewline ? '\n' : ''}`; + const updated = `${left}${inserted}${right}`; + + await writeFile(absolutePath, updated, 'utf8'); + + return { + content: [ + { + type: 'text', + text: `Inserted form ${params.position} "${params.anchorName}" (line ${anchor.line}) in ${params.path}.`, + }, + ], + details: { + path: params.path, + absolutePath, + anchorName: params.anchorName, + position: params.position, + line: anchor.line, + }, + }; + }); + }, + }); + + pi.registerTool({ + name: 'pigibrack_delete_form', + label: 'pigibrack delete form', + description: 'Delete a top-level Scheme form by name.', + promptSnippet: 'Delete a top-level Scheme form by its name.', + parameters: Type.Object({ + path: Type.String({ description: 'Path to a Scheme source file' }), + name: Type.String({ description: 'Top-level form name to delete' }), + }), + async execute(_toolCallId, params, _signal, _onUpdate, ctx) { + const absolutePath = resolve(ctx.cwd, normalizeUserPath(params.path)); + + return withFileMutationQueue(absolutePath, async () => { + const source = await readFile(absolutePath, 'utf8'); + const forms = parseTopLevelForms(source); + const form = uniqueByName(forms, params.name); + + let start = form.start; + let end = form.end; + + if (source[end] === '\n') end += 1; + if (start > 0 && source[start - 1] === '\n' && source[end] === '\n') start -= 1; + + const updated = `${source.slice(0, start)}${source.slice(end)}`; + await writeFile(absolutePath, updated, 'utf8'); + + return { + content: [{ type: 'text', text: `Deleted form "${params.name}" from ${params.path}.` }], + details: { + path: params.path, + absolutePath, + name: params.name, + line: form.line, + }, + }; + }); + }, + }); + + pi.registerTool({ + name: 'pigibrack_check_syntax', + label: 'pigibrack check syntax', + description: + 'Check Scheme syntax via guile reader. Accepts either a file path or inline source.', + promptSnippet: 'Validate Scheme syntax before editing or evaluating.', + parameters: Type.Object({ + path: Type.Optional(Type.String({ description: 'Path to a Scheme source file' })), + source: Type.Optional(Type.String({ description: 'Inline Scheme source to validate' })), + }), + async execute(_toolCallId, params, signal, _onUpdate, ctx) { + if (!params.path && typeof params.source !== 'string') { + throw new Error('Provide either path or source.'); + } + + if (params.path && typeof params.source === 'string') { + throw new Error('Provide path or source, not both.'); + } + + const resolvedPath = params.path + ? resolve(ctx.cwd, normalizeUserPath(params.path)) + : undefined; + const result = await guileSyntaxCheck({ path: resolvedPath, source: params.source }, signal); + + const output = result.valid + ? 'Syntax check: valid ✅' + : `Syntax check: invalid ❌\n\n${result.errors.map((error, index) => `${index + 1}. ${error}`).join('\n')}`; + + return { + content: [{ type: 'text', text: formatTruncated(output, 'head') }], + details: { + valid: result.valid, + errors: result.errors, + path: params.path, + }, + }; + }, + }); + + pi.registerTool({ + name: 'pigibrack_macro_expand', + label: 'pigibrack macro expand', + description: + 'Macro-expand a Scheme expression in guile. Optional module is a module spec, e.g. (my module).', + promptSnippet: + 'Expand a Scheme form to inspect macro output before debugging runtime behavior.', + parameters: Type.Object({ + expr: Type.String({ description: 'A Scheme expression to macro-expand' }), + module: Type.Optional(Type.String({ description: 'Optional module spec, e.g. (my module)' })), + }), + async execute(_toolCallId, params, signal, _onUpdate, ctx) { + const normalizedExpr = ensureSingleTopLevelForm(params.expr); + const expanded = await guileMacroExpand(normalizedExpr, params.module, ctx.cwd, signal); + + const output = `expanded:\n${expanded || ''}`; + + return { + content: [{ type: 'text', text: formatTruncated(output, 'tail') }], + details: { + module: params.module, + }, + }; + }, + }); + + pi.registerTool({ + name: 'pigibrack_eval_expr', + label: 'pigibrack eval expr', + description: `Evaluate a Scheme expression in guile. Optional module is a module spec, e.g. (my module). ${TOOL_DESCRIPTION_SUFFIX}`, + promptSnippet: 'Evaluate Scheme expressions in guile for fast feedback.', + promptGuidelines: [ + 'Use pigibrack_eval_expr after structural edits to validate behavior quickly.', + ], + parameters: Type.Object({ + expr: Type.String({ description: 'A Scheme expression to evaluate' }), + module: Type.Optional(Type.String({ description: 'Optional module spec, e.g. (my module)' })), + }), + async execute(_toolCallId, params, signal, _onUpdate, ctx) { + const result = await guileEval(params.expr, params.module, ctx.cwd, signal); + + const outputParts = [] as string[]; + if (result.stdout.trim()) { + outputParts.push(`stdout:\n${result.stdout}`); + } + outputParts.push(`result:\n${result.value || ''}`); + + return { + content: [{ type: 'text', text: formatTruncated(outputParts.join('\n\n'), 'tail') }], + details: { + module: params.module, + hasStdout: result.stdout.trim().length > 0, + }, + }; + }, + }); +} diff --git a/package-lock.json b/package-lock.json index 8eb69c3..3744707 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,25 @@ { "name": "pigibrack", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "pigibrack", + "version": "0.1.0", + "license": "BSD-2-Clause", "devDependencies": { "@mariozechner/pi-coding-agent": "^0.65.0" + }, + "peerDependencies": { + "@mariozechner/pi-ai": "*", + "@mariozechner/pi-coding-agent": "*" } }, "node_modules/@anthropic-ai/sdk": { "version": "0.73.0", "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.73.0.tgz", "integrity": "sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw==", - "dev": true, "license": "MIT", "dependencies": { "json-schema-to-ts": "^3.1.1" @@ -33,7 +40,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", @@ -48,7 +54,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", @@ -64,7 +69,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -77,7 +81,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", @@ -91,7 +94,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", @@ -105,7 +107,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^5.2.0", @@ -120,7 +121,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -130,7 +130,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.222.0", @@ -142,7 +141,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -155,7 +153,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", @@ -169,7 +166,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", @@ -183,7 +179,6 @@ "version": "3.1024.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1024.0.tgz", "integrity": "sha512-nIhsn0/eYrL2fTh4kMO7Hpfmhv+AkkXl0KGNpD6+fdmotGvRBWcDv9/PmP/+sT6gvrKTYyzH3vu4efpTPzzP0Q==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -242,7 +237,6 @@ "version": "3.973.26", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.973.26.tgz", "integrity": "sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -267,7 +261,6 @@ "version": "3.972.24", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.24.tgz", "integrity": "sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -284,7 +277,6 @@ "version": "3.972.26", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.26.tgz", "integrity": "sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -306,7 +298,6 @@ "version": "3.972.28", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.28.tgz", "integrity": "sha512-wXYvq3+uQcZV7k+bE4yDXCTBdzWTU9x/nMiKBfzInmv6yYK1veMK0AKvRfRBd72nGWYKcL6AxwiPg9z/pYlgpw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -332,7 +323,6 @@ "version": "3.972.28", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.28.tgz", "integrity": "sha512-ZSTfO6jqUTCysbdBPtEX5OUR//3rbD0lN7jO3sQeS2Gjr/Y+DT6SbIJ0oT2cemNw3UzKu97sNONd1CwNMthuZQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -352,7 +342,6 @@ "version": "3.972.29", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.29.tgz", "integrity": "sha512-clSzDcvndpFJAggLDnDb36sPdlZYyEs5Zm6zgZjjUhwsJgSWiWKwFIXUVBcbruidNyBdbpOv2tNDL9sX8y3/0g==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.24", @@ -376,7 +365,6 @@ "version": "3.972.24", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.24.tgz", "integrity": "sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -394,7 +382,6 @@ "version": "3.972.28", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.28.tgz", "integrity": "sha512-IoUlmKMLEITFn1SiCTjPfR6KrE799FBo5baWyk/5Ppar2yXZoUdaRqZzJzK6TcJxx450M8m8DbpddRVYlp5R/A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -414,7 +401,6 @@ "version": "3.1021.0", "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1021.0.tgz", "integrity": "sha512-TKY6h9spUk3OLs5v1oAgW9mAeBE3LAGNBwJokLy96wwmd4W2v/tYlXseProyed9ValDj2u1jK/4Rg1T+1NXyJA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -433,7 +419,6 @@ "version": "3.972.28", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.28.tgz", "integrity": "sha512-d+6h0SD8GGERzKe27v5rOzNGKOl0D+l0bWJdqrxH8WSQzHzjsQFIAPgIeOTUwBHVsKKwtSxc91K/SWax6XgswQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -452,7 +437,6 @@ "version": "3.972.12", "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.12.tgz", "integrity": "sha512-ruyc/MNR6e+cUrGCth7fLQ12RXBZDy/bV06tgqB9Z5n/0SN/C0m6bsQEV8FF9zPI6VSAOaRd0rNgmpYVnGawrQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -468,7 +452,6 @@ "version": "3.972.8", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.8.tgz", "integrity": "sha512-r+oP+tbCxgqXVC3pu3MUVePgSY0ILMjA+aEwOosS77m3/DRbtvHrHwqvMcw+cjANMeGzJ+i0ar+n77KXpRA8RQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -484,7 +467,6 @@ "version": "3.972.8", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.8.tgz", "integrity": "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -500,7 +482,6 @@ "version": "3.972.8", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.8.tgz", "integrity": "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -515,7 +496,6 @@ "version": "3.972.9", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.9.tgz", "integrity": "sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -532,7 +512,6 @@ "version": "3.972.28", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.28.tgz", "integrity": "sha512-cfWZFlVh7Va9lRay4PN2A9ARFzaBYcA097InT5M2CdRS05ECF5yaz86jET8Wsl2WcyKYEvVr/QNmKtYtafUHtQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -552,7 +531,6 @@ "version": "3.972.14", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.14.tgz", "integrity": "sha512-qnfDlIHjm6DrTYNvWOUbnZdVKgtoKbO/Qzj+C0Wp5Y7VUrsvBRQtGKxD+hc+mRTS4N0kBJ6iZ3+zxm4N1OSyjg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -576,7 +554,6 @@ "version": "3.996.18", "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.18.tgz", "integrity": "sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", @@ -626,7 +603,6 @@ "version": "3.972.10", "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.10.tgz", "integrity": "sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -643,7 +619,6 @@ "version": "3.1024.0", "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1024.0.tgz", "integrity": "sha512-eoyTMgd6OzoE1dq50um5Y53NrosEkWsjH0W6pswi7vrv1W9hY/7hR43jDcPevqqj+OQksf/5lc++FTqRlb8Y1Q==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/core": "^3.973.26", @@ -662,7 +637,6 @@ "version": "3.973.6", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.6.tgz", "integrity": "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -676,7 +650,6 @@ "version": "3.996.5", "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.5.tgz", "integrity": "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -693,7 +666,6 @@ "version": "3.972.8", "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.972.8.tgz", "integrity": "sha512-J6DS9oocrgxM8xlUTTmQOuwRF6rnAGEujAN9SAzllcrQmwn5iJ58ogxy3SEhD0Q7JZvlA5jvIXBkpQRqEqlE9A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -709,7 +681,6 @@ "version": "3.965.5", "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -722,7 +693,6 @@ "version": "3.972.8", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.8.tgz", "integrity": "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.973.6", @@ -735,7 +705,6 @@ "version": "3.973.14", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.14.tgz", "integrity": "sha512-vNSB/DYaPOyujVZBg/zUznH9QC142MaTHVmaFlF7uzzfg3CgT9f/l4C0Yi+vU/tbBhxVcXVB90Oohk5+o+ZbWw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.28", @@ -761,7 +730,6 @@ "version": "3.972.16", "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.16.tgz", "integrity": "sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -776,7 +744,6 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18.0.0" @@ -786,7 +753,6 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -807,7 +773,6 @@ "version": "1.48.0", "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.48.0.tgz", "integrity": "sha512-plonYK4ML2PrxsRD9SeqmFt76eREWkQdPCglOA6aYDzL1AAbE+7PUnT54SvpWGfws13L0AZEqGSpL7+1IPnTxQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "google-auth-library": "^10.3.0", @@ -1048,7 +1013,6 @@ "version": "0.65.0", "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.65.0.tgz", "integrity": "sha512-MsCsCHlHIlBYbg6jB2PJBeCNKbjzVZge7ddBNUJN2gsFY8sdjFh482+GB+r5Ou6k9Fnhi3nO779YDymo5+t89w==", - "dev": true, "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "^0.73.0", @@ -1134,7 +1098,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.14.1.tgz", "integrity": "sha512-IiLmmZFCCTReQgPAT33r7KQ1nYo5JPdvGkrkZqA8qQ2qB1GHgs5LoP5K2ICyrjnpw2n8oSxMM/VP+liiKcGNlQ==", - "dev": true, "dependencies": { "ws": "^8.18.0", "zod": "^3.25.0 || ^4.0.0", @@ -1145,35 +1108,30 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.1", @@ -1184,35 +1142,30 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/@silvia-odwyer/photon-node": { @@ -1226,14 +1179,12 @@ "version": "0.34.49", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", - "dev": true, "license": "MIT" }, "node_modules/@smithy/config-resolver": { "version": "4.4.13", "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.13.tgz", "integrity": "sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.12", @@ -1251,7 +1202,6 @@ "version": "3.23.13", "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.13.tgz", "integrity": "sha512-J+2TT9D6oGsUVXVEMvz8h2EmdVnkBiy2auCie4aSJMvKlzUtO5hqjEzXhoCUkIMo7gAYjbQcN0g/MMSXEhDs1Q==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.3.12", @@ -1273,7 +1223,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.12.tgz", "integrity": "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.12", @@ -1290,7 +1239,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.12.tgz", "integrity": "sha512-FE3bZdEl62ojmy8x4FHqxq2+BuOHlcxiH5vaZ6aqHJr3AIZzwF5jfx8dEiU/X0a8RboyNDjmXjlbr8AdEyLgiA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@aws-crypto/crc32": "5.2.0", @@ -1306,7 +1254,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.12.tgz", "integrity": "sha512-XUSuMxlTxV5pp4VpqZf6Sa3vT/Q75FVkLSpSSE3KkWBvAQWeuWt1msTv8fJfgA4/jcJhrbrbMzN1AC/hvPmm5A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.12", @@ -1321,7 +1268,6 @@ "version": "4.3.12", "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.12.tgz", "integrity": "sha512-7epsAZ3QvfHkngz6RXQYseyZYHlmWXSTPOfPmXkiS+zA6TBNo1awUaMFL9vxyXlGdoELmCZyZe1nQE+imbmV+Q==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1335,7 +1281,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.12.tgz", "integrity": "sha512-D1pFuExo31854eAvg89KMn9Oab/wEeJR6Buy32B49A9Ogdtx5fwZPqBHUlDzaCDpycTFk2+fSQgX689Qsk7UGA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.12", @@ -1350,7 +1295,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.12.tgz", "integrity": "sha512-+yNuTiyBACxOJUTvbsNsSOfH9G9oKbaJE1lNL3YHpGcuucl6rPZMi3nrpehpVOVR2E07YqFFmtwpImtpzlouHQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/eventstream-codec": "^4.2.12", @@ -1365,7 +1309,6 @@ "version": "5.3.15", "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.15.tgz", "integrity": "sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.3.12", @@ -1382,7 +1325,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.12.tgz", "integrity": "sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1398,7 +1340,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.12.tgz", "integrity": "sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1412,7 +1353,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.2.tgz", "integrity": "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1425,7 +1365,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.12.tgz", "integrity": "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.3.12", @@ -1440,7 +1379,6 @@ "version": "4.4.28", "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.28.tgz", "integrity": "sha512-p1gfYpi91CHcs5cBq982UlGlDrxoYUX6XdHSo91cQ2KFuz6QloHosO7Jc60pJiVmkWrKOV8kFYlGFFbQ2WUKKQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.23.13", @@ -1460,7 +1398,6 @@ "version": "4.4.46", "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.46.tgz", "integrity": "sha512-SpvWNNOPOrKQGUqZbEPO+es+FRXMWvIyzUKUOYdDgdlA6BdZj/R58p4umoQ76c2oJC44PiM7mKizyyex1IJzow==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.12", @@ -1481,7 +1418,6 @@ "version": "4.2.16", "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.16.tgz", "integrity": "sha512-beqfV+RZ9RSv+sQqor3xroUUYgRFCGRw6niGstPG8zO9LgTl0B0MCucxjmrH/2WwksQN7UUgI7KNANoZv+KALA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.23.13", @@ -1497,7 +1433,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.12.tgz", "integrity": "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1511,7 +1446,6 @@ "version": "4.3.12", "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.12.tgz", "integrity": "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.2.12", @@ -1527,7 +1461,6 @@ "version": "4.5.1", "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.5.1.tgz", "integrity": "sha512-ejjxdAXjkPIs9lyYyVutOGNOraqUE9v/NjGMKwwFrfOM354wfSD8lmlj8hVwUzQmlLLF4+udhfCX9Exnbmvfzw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^5.3.12", @@ -1543,7 +1476,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.12.tgz", "integrity": "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1557,7 +1489,6 @@ "version": "5.3.12", "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.12.tgz", "integrity": "sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1571,7 +1502,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.12.tgz", "integrity": "sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1586,7 +1516,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.12.tgz", "integrity": "sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1600,7 +1529,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.12.tgz", "integrity": "sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1" @@ -1613,7 +1541,6 @@ "version": "4.4.7", "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.7.tgz", "integrity": "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1627,7 +1554,6 @@ "version": "5.3.12", "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.12.tgz", "integrity": "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.2", @@ -1647,7 +1573,6 @@ "version": "4.12.8", "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.8.tgz", "integrity": "sha512-aJaAX7vHe5i66smoSSID7t4rKY08PbD8EBU7DOloixvhOozfYWdcSYE4l6/tjkZ0vBZhGjheWzB2mh31sLgCMA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/core": "^3.23.13", @@ -1666,7 +1591,6 @@ "version": "4.13.1", "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz", "integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1679,7 +1603,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.12.tgz", "integrity": "sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/querystring-parser": "^4.2.12", @@ -1694,7 +1617,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.2.tgz", "integrity": "sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^4.2.2", @@ -1709,7 +1631,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.2.tgz", "integrity": "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1722,7 +1643,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.3.tgz", "integrity": "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1735,7 +1655,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.2.tgz", "integrity": "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^4.2.2", @@ -1749,7 +1668,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.2.tgz", "integrity": "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1762,7 +1680,6 @@ "version": "4.3.44", "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.44.tgz", "integrity": "sha512-eZg6XzaCbVr2S5cAErU5eGBDaOVTuTo1I65i4tQcHENRcZ8rMWhQy1DaIYUSLyZjsfXvmCqZrstSMYyGFocvHA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.2.12", @@ -1778,7 +1695,6 @@ "version": "4.2.48", "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.48.tgz", "integrity": "sha512-FqOKTlqSaoV3nzO55pMs5NBnZX8EhoI0DGmn9kbYeXWppgHD6dchyuj2HLqp4INJDJbSrj6OFYJkAh/WhSzZPg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/config-resolver": "^4.4.13", @@ -1797,7 +1713,6 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.3.3.tgz", "integrity": "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.12", @@ -1812,7 +1727,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.2.tgz", "integrity": "sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1825,7 +1739,6 @@ "version": "4.2.12", "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.12.tgz", "integrity": "sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/types": "^4.13.1", @@ -1839,7 +1752,6 @@ "version": "4.2.13", "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.13.tgz", "integrity": "sha512-qQQsIvL0MGIbUjeSrg0/VlQ3jGNKyM3/2iU3FPNgy01z+Sp4OvcaxbgIoFOTvB61ZoohtutuOvOcgmhbD0katQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/service-error-classification": "^4.2.12", @@ -1854,7 +1766,6 @@ "version": "4.5.21", "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.21.tgz", "integrity": "sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", @@ -1874,7 +1785,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.2.tgz", "integrity": "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1887,7 +1797,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.2.tgz", "integrity": "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^4.2.2", @@ -1901,7 +1810,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.2.tgz", "integrity": "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==", - "dev": true, "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -1939,7 +1847,6 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "dev": true, "license": "MIT" }, "node_modules/@types/mime-types": { @@ -1953,7 +1860,6 @@ "version": "25.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.18.0" @@ -1963,7 +1869,6 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true, "license": "MIT" }, "node_modules/@types/yauzl": { @@ -1981,7 +1886,6 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -1991,7 +1895,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3", @@ -2008,7 +1911,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, "license": "MIT", "dependencies": { "ajv": "^8.0.0" @@ -2062,7 +1964,6 @@ "version": "0.13.4", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "dev": true, "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -2085,7 +1986,6 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, "funding": [ { "type": "github", @@ -2106,7 +2006,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -2116,7 +2015,6 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -2126,7 +2024,6 @@ "version": "2.14.1", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "dev": true, "license": "MIT" }, "node_modules/brace-expansion": { @@ -2156,14 +2053,12 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/chalk": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -2270,7 +2165,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 12" @@ -2280,7 +2174,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2298,7 +2191,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", - "dev": true, "license": "MIT", "dependencies": { "ast-types": "^0.13.4", @@ -2323,7 +2215,6 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -2360,7 +2251,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", @@ -2382,7 +2272,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -2396,7 +2285,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -2406,7 +2294,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -2416,7 +2303,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, "license": "MIT" }, "node_modules/extract-zip": { @@ -2444,14 +2330,12 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", - "dev": true, "funding": [ { "type": "github", @@ -2468,7 +2352,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", - "dev": true, "funding": [ { "type": "github", @@ -2484,7 +2367,6 @@ "version": "5.5.8", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz", "integrity": "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==", - "dev": true, "funding": [ { "type": "github", @@ -2515,7 +2397,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dev": true, "funding": [ { "type": "github", @@ -2558,7 +2439,6 @@ "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, "license": "MIT", "dependencies": { "fetch-blob": "^3.1.2" @@ -2571,7 +2451,6 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "extend": "^3.0.2", @@ -2586,7 +2465,6 @@ "version": "8.1.2", "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", - "dev": true, "license": "Apache-2.0", "dependencies": { "gaxios": "^7.0.0", @@ -2640,7 +2518,6 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", - "dev": true, "license": "MIT", "dependencies": { "basic-ftp": "^5.0.2", @@ -2655,7 +2532,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -2683,7 +2559,6 @@ "version": "10.6.2", "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "base64-js": "^1.3.0", @@ -2701,7 +2576,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=14" @@ -2751,7 +2625,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -2765,7 +2638,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -2810,7 +2682,6 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", - "dev": true, "license": "MIT", "engines": { "node": ">= 12" @@ -2830,7 +2701,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "dev": true, "license": "MIT", "dependencies": { "bignumber.js": "^9.0.0" @@ -2840,7 +2710,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", @@ -2854,14 +2723,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, "license": "MIT" }, "node_modules/jwa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", - "dev": true, "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -2873,7 +2740,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", - "dev": true, "license": "MIT", "dependencies": { "jwa": "^2.0.1", @@ -2896,7 +2762,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "dev": true, "license": "Apache-2.0" }, "node_modules/lru-cache": { @@ -2979,7 +2844,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -2998,7 +2862,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -3009,7 +2872,6 @@ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", "deprecated": "Use your platform's native DOMException instead", - "dev": true, "funding": [ { "type": "github", @@ -3029,7 +2891,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dev": true, "license": "MIT", "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -3068,7 +2929,6 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", - "dev": true, "license": "Apache-2.0", "bin": { "openai": "bin/cli" @@ -3090,7 +2950,6 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/retry": "0.12.0", @@ -3104,7 +2963,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", - "dev": true, "license": "MIT", "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", @@ -3124,7 +2982,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", - "dev": true, "license": "MIT", "dependencies": { "degenerator": "^5.0.0", @@ -3162,14 +3019,12 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", - "dev": true, "license": "MIT" }, "node_modules/path-expression-matcher": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.2.1.tgz", "integrity": "sha512-d7gQQmLvAKXKXE2GeP9apIGbMYKz88zWdsn/BN2HRWVQsDFdUY36WSLTY0Jvd4HWi7Fb30gQ62oAOzdgJA6fZw==", - "dev": true, "funding": [ { "type": "github", @@ -3231,7 +3086,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", - "dev": true, "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -3256,7 +3110,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -3276,7 +3129,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -3286,7 +3138,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, "license": "MIT" }, "node_modules/pump": { @@ -3314,7 +3165,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3324,7 +3174,6 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -3334,7 +3183,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -3362,7 +3210,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6.0.0", @@ -3373,7 +3220,6 @@ "version": "2.8.7", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "dev": true, "license": "MIT", "dependencies": { "ip-address": "^10.0.1", @@ -3388,7 +3234,6 @@ "version": "8.0.5", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -3403,7 +3248,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "license": "BSD-3-Clause", "optional": true, "engines": { @@ -3475,7 +3319,6 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.2.tgz", "integrity": "sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==", - "dev": true, "funding": [ { "type": "github", @@ -3560,14 +3403,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", - "dev": true, "license": "MIT" }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/uint8array-extras": { @@ -3587,7 +3428,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.7.tgz", "integrity": "sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=20.18.1" @@ -3597,14 +3437,12 @@ "version": "7.18.2", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, "license": "MIT" }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -3662,7 +3500,6 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -3763,7 +3600,6 @@ "version": "4.3.6", "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -3773,7 +3609,6 @@ "version": "3.25.2", "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", - "dev": true, "license": "ISC", "peerDependencies": { "zod": "^3.25.28 || ^4" diff --git a/package.json b/package.json index a125c05..c3946bc 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,36 @@ { + "name": "pigibrack", + "version": "0.1.0", + "description": "Pi extension package for structural Scheme/Guile editing with a persistent REPL sidecar", + "license": "BSD-2-Clause", + "keywords": [ + "pi-package", + "pi-extension", + "scheme", + "guile", + "lisp" + ], + "files": [ + "extensions/pigibrack/**", + "README.md", + "LICENSE" + ], + "pi": { + "extensions": [ + "./extensions/pigibrack/index.ts" + ] + }, + "peerDependencies": { + "@mariozechner/pi-ai": "*", + "@mariozechner/pi-coding-agent": "*" + }, "devDependencies": { "@mariozechner/pi-coding-agent": "^0.65.0" }, "scripts": { "typecheck": "tsc --noEmit", "format": "prettier . --write", - "format:check": "prettier . --check" + "format:check": "prettier . --check", + "pack:dry-run": "npm pack --dry-run" } }