Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/audiobook-curator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ not the Markdown presentation or an intermediate Suspense fallback, so existing
receipt consumers do not change when a command becomes rendered.

`src/operations/` owns shared operation handlers and schemas;
`src/cli-command.ts` defines their small typed definition helper. Domain logic
`src/cli-command.ts` names the `{ signal }` context every handler receives. Domain logic
remains in `src/` over `foundation.ts` and `media-process.ts`, while
`src/index.ts` remains the package library entry.

Expand Down
36 changes: 5 additions & 31 deletions examples/audiobook-curator/src/cli-command.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,11 @@
/**
* The operation-definition helper behind `src/operations/*.ts`: one shared
* core (`id`, `inputSchema`, `handler`, `resultSchema`) that the generated
* MCP routes and the routed `src/cli/` commands both consume. The manual
* CLI projection (`cli.parse`/`usage`/`exitCode`) and its `runCliCommands`
* dispatcher were retired by the #102 stage-3 migration — the framework
* compiles `src/cli/**` routes into the executable instead.
* The context every `src/operations/*.ts` handler receives from the generated
* MCP routes and the routed `src/cli/` commands. The manual CLI projection
* (`cli.parse`/`usage`/`exitCode`) and its `runCliCommands` dispatcher were
* retired by the #102 stage-3 migration — the framework compiles `src/cli/**`
* routes into the executable instead.
*/

export interface CliCommandContext {
readonly signal: AbortSignal;
}

interface Schema<Output> {
readonly _output: Output;
parse(value: unknown): Output;
}

/** Exported so consumer declaration emit can name the registry types (#174). */
export interface CliCommandDefinition<
InputSchema extends Schema<unknown>,
ResultSchema extends Schema<unknown>,
HandlerInput,
> {
readonly handler: (input: HandlerInput, context: CliCommandContext) => unknown;
readonly id: string;
readonly inputSchema: InputSchema;
readonly resultSchema: ResultSchema;
}

export const defineCliCommand = <
InputSchema extends Schema<unknown>,
ResultSchema extends Schema<unknown>,
HandlerInput,
>(
definition: CliCommandDefinition<InputSchema, ResultSchema, HandlerInput>,
): CliCommandDefinition<InputSchema, ResultSchema, HandlerInput> => Object.freeze(definition);
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/acoustic-identify.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { defaultEvidenceOperations, evidenceOperations } from '../operations/evidence.js';
import { evidenceOperations } from '../operations/evidence.js';

const operation = evidenceOperations(defaultEvidenceOperations).acousticIdentify;
const operation = evidenceOperations.acousticIdentify;

export const config = {
description: 'Try score-ranked, deduplicated Audible candidates and retain per-candidate evidence.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/acoustic-verify.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { defaultEvidenceOperations, evidenceOperations } from '../operations/evidence.js';
import { evidenceOperations } from '../operations/evidence.js';

const operation = evidenceOperations(defaultEvidenceOperations).acousticVerify;
const operation = evidenceOperations.acousticVerify;

export const config = {
description: 'Compare one bounded Audible sample with local audio through optional Audiolocate.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/apply-chapters.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { defaultMediaMutationOperations, mediaMutationOperations } from '../operations/media-mutation.js';
import { mediaMutationOperations } from '../operations/media-mutation.js';

const operation = mediaMutationOperations(defaultMediaMutationOperations).applyChapters;
const operation = mediaMutationOperations.applyChapters;

export const config = {
description: 'Plan or apply verified generic or Audible chapter rows without changing encoded audio.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/apply-metadata.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { defaultMediaMutationOperations, mediaMutationOperations } from '../operations/media-mutation.js';
import { mediaMutationOperations } from '../operations/media-mutation.js';

const operation = mediaMutationOperations(defaultMediaMutationOperations).applyMetadata;
const operation = mediaMutationOperations.applyMetadata;

export const config = {
description: 'Plan or apply verified Audible metadata and artwork without changing encoded audio.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/audible-cache.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { audibleOperations, defaultAudibleOperations } from '../operations/audible.js';
import { audibleOperations } from '../operations/audible.js';

const operation = audibleOperations(defaultAudibleOperations).audibleCache;
const operation = audibleOperations.audibleCache;

export const config = {
description: 'Cache one reviewed Audible product, chapters, artwork, and source URLs.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/audible-search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { z } from 'zod';
import type { AudibleSearchReceipt } from '../audible.js';
import { SearchRanking } from '../components/candidate-ranking.js';
import { audibleSearchHeadline } from '../components/headlines.js';
import { audibleOperations, audibleRegionList, defaultAudibleOperations } from '../operations/audible.js';
import { audibleOperations, audibleRegionList } from '../operations/audible.js';

const operation = audibleOperations(defaultAudibleOperations).audibleSearch;
const operation = audibleOperations.audibleSearch;

export const config = {
description: 'Search and rank Audible identity candidates across reviewed regions.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/audible-select.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { audibleOperations, defaultAudibleOperations } from '../operations/audible.js';
import { audibleOperations } from '../operations/audible.js';

const operation = audibleOperations(defaultAudibleOperations).audibleSelect;
const operation = audibleOperations.audibleSelect;

export const config = {
description: 'Record one explicit human-reviewed Audible edition choice.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/audit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { ChapterOutline, chaptersFromAuditReceipt } from '../components/chapter-
import { integrityAuditHeadline } from '../components/headlines.js';
import { IntegrityAuditReport } from '../components/integrity-report.js';
import type { IntegrityAuditReceipt } from '../integrity-audit.js';
import { defaultOutputOperations, outputOperations } from '../operations/output.js';
import { outputOperations } from '../operations/output.js';

const operation = outputOperations(defaultOutputOperations).audit;
const operation = outputOperations.audit;

export const config = {
description: 'Validate metadata, chapters, source mapping, hashes, and optional complete decode.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/convert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import { convertHeadline } from '../components/headlines.js';
import { ConversionIntegrityReport } from '../components/integrity-report.js';
import { ConversionMutation } from '../components/mutation-receipt.js';
import type { ConvertReceipt } from '../conversion.js';
import { defaultOutputOperations, outputOperations } from '../operations/output.js';
import { outputOperations } from '../operations/output.js';

const operation = outputOperations(defaultOutputOperations).convert;
const operation = outputOperations.convert;

export const config = {
description: 'Plan or apply a verified conversion to one chaptered M4B.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/inspect.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { defaultDiscoveryOperations, discoveryOperations } from '../operations/discovery.js';
import { discoveryOperations } from '../operations/discovery.js';

const operation = discoveryOperations(defaultDiscoveryOperations).inspect;
const operation = discoveryOperations.inspect;

export const config = {
description: 'Inspect a bounded audiobook source tree without changing it.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/inventory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { z } from 'zod';
import { inventoryHeadline } from '../components/headlines.js';
import { InventoryShelf } from '../components/library-shelf.js';
import type { InventoryReceipt } from '../library.js';
import { defaultDiscoveryOperations, discoveryOperations } from '../operations/discovery.js';
import { discoveryOperations } from '../operations/discovery.js';

const operation = discoveryOperations(defaultDiscoveryOperations).inventory;
const operation = discoveryOperations.inventory;

export const config = {
description: 'Probe source audio without changing it.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/library-audit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { libraryAuditCliHeadline } from '../components/headlines.js';
import { LibraryAnalysis } from '../components/library-analysis.js';
import { DataList } from '../components/primitives.js';
import type { LibraryAuditReceipt } from '../library.js';
import { defaultDiscoveryOperations, discoveryOperations } from '../operations/discovery.js';
import { discoveryOperations } from '../operations/discovery.js';

const operation = discoveryOperations(defaultDiscoveryOperations).libraryAudit;
const operation = discoveryOperations.libraryAudit;

/**
* The rendered command of this CLI (#102 stage 3): the audit is the
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/prepare.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { defaultOutputOperations, outputOperations } from '../operations/output.js';
import { outputOperations } from '../operations/output.js';

const operation = outputOperations(defaultOutputOperations).prepare;
const operation = outputOperations.prepare;

export const config = {
description: 'Plan an M4B output or apply the plan when explicitly requested.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { z } from 'zod';
import { selectionHeadline } from '../components/headlines.js';
import { SelectionShelf } from '../components/library-shelf.js';
import type { SelectionReceipt } from '../library.js';
import { defaultDiscoveryOperations, discoveryOperations } from '../operations/discovery.js';
import { discoveryOperations } from '../operations/discovery.js';

const operation = discoveryOperations(defaultDiscoveryOperations).select;
const operation = discoveryOperations.select;

export const config = {
description: 'Choose the strongest source among normalized collisions.',
Expand Down
4 changes: 2 additions & 2 deletions examples/audiobook-curator/src/cli/whisper-verify.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type { CliRouteConfig, CliRouteProps } from 'agent-bundle';
import { z } from 'zod';

import { defaultEvidenceOperations, evidenceOperations } from '../operations/evidence.js';
import { evidenceOperations } from '../operations/evidence.js';

const operation = evidenceOperations(defaultEvidenceOperations).whisperVerify;
const operation = evidenceOperations.whisperVerify;

export const config = {
description: 'Transcribe distributed audiobook windows for human language and identity review.',
Expand Down
20 changes: 5 additions & 15 deletions examples/audiobook-curator/src/foundation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { createHash } from 'node:crypto';
import { createReadStream } from 'node:fs';
import { open, mkdir, mkdtemp, rename, rm, writeFile } from 'node:fs/promises';
import { dirname, extname, join, resolve } from 'node:path';
import { pipeline } from 'node:stream/promises';

export const audioExtensions = Object.freeze(new Set([
'.aac', '.aax', '.aaxc', '.aif', '.aiff', '.flac', '.m4a', '.m4b',
Expand Down Expand Up @@ -49,21 +51,9 @@ export const escapeFfmetadata = (value: string): string => value
.replaceAll('\n', '\\n');

export const sha256File = async (path: string): Promise<string> => {
const handle = await open(path, 'r');
try {
const hash = createHash('sha256');
const buffer = Buffer.allocUnsafe(1024 * 1024);
let position = 0;
while (true) {
const result = await handle.read(buffer, 0, buffer.length, position);
if (result.bytesRead === 0) break;
hash.update(buffer.subarray(0, result.bytesRead));
position += result.bytesRead;
}
return hash.digest('hex');
} finally {
await handle.close();
}
const hash = createHash('sha256');
await pipeline(createReadStream(path), hash);
return hash.digest('hex');
};

export const mapWithConcurrency = async <T, R>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { CurationShelf, ShelfUnavailable } from '../../../components/curation-sh
import { ChapterIntegrityReport } from '../../../components/integrity-report.js';
import { ChapterMutation } from '../../../components/mutation-receipt.js';
import type { ChapterReceipt } from '../../../media-mutation.js';
import { defaultMediaMutationOperations, mediaMutationOperations } from '../../../operations/media-mutation.js';
import { mediaMutationOperations } from '../../../operations/media-mutation.js';
import { CurationShelfStateSchema } from '../../../state.js';

const operation = mediaMutationOperations(defaultMediaMutationOperations).applyChapters;
const operation = mediaMutationOperations.applyChapters;

export const config = {
annotations: { destructiveHint: true, readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { CurationShelf, ShelfUnavailable } from '../../../components/curation-sh
import { MetadataIntegrityReport } from '../../../components/integrity-report.js';
import { MetadataMutation } from '../../../components/mutation-receipt.js';
import type { MetadataReceipt } from '../../../media-mutation.js';
import { defaultMediaMutationOperations, mediaMutationOperations } from '../../../operations/media-mutation.js';
import { mediaMutationOperations } from '../../../operations/media-mutation.js';
import { CurationShelfStateSchema } from '../../../state.js';

const operation = mediaMutationOperations(defaultMediaMutationOperations).applyMetadata;
const operation = mediaMutationOperations.applyMetadata;

export const config = {
annotations: { destructiveHint: true, readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { ChapterOutline, chaptersFromAuditReceipt } from '../../../components/ch
import { integrityAuditHeadline } from '../../../components/headlines.js';
import { IntegrityAuditReport } from '../../../components/integrity-report.js';
import type { IntegrityAuditReceipt } from '../../../integrity-audit.js';
import { defaultOutputOperations, outputOperations } from '../../../operations/output.js';
import { outputOperations } from '../../../operations/output.js';

const operation = outputOperations(defaultOutputOperations).audit;
const operation = outputOperations.audit;

export const config = {
annotations: { readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { libraryAuditHeadline } from '../../../components/headlines.js';
import { LibraryAnalysis } from '../../../components/library-analysis.js';
import { AuditFileCards, AuditSummary } from '../../../components/library-shelf.js';
import type { LibraryAuditReceipt } from '../../../library.js';
import { defaultDiscoveryOperations, discoveryOperations } from '../../../operations/discovery.js';
import { discoveryOperations } from '../../../operations/discovery.js';

const operation = discoveryOperations(defaultDiscoveryOperations).libraryAudit;
const operation = discoveryOperations.libraryAudit;

export const config = {
annotations: { readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import type { ToolRouteProps } from 'agent-bundle';

import type { AudibleCacheReceipt } from '../../../audible.js';
import { Callout, DataList } from '../../../components/primitives.js';
import { defaultAudibleOperations, audibleOperations } from '../../../operations/audible.js';
import { audibleOperations } from '../../../operations/audible.js';

const operation = audibleOperations(defaultAudibleOperations).audibleCache;
const operation = audibleOperations.audibleCache;

export const config = {
annotations: { openWorldHint: true, readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { convertHeadline } from '../../../components/headlines.js';
import { ConversionIntegrityReport } from '../../../components/integrity-report.js';
import { ConversionMutation } from '../../../components/mutation-receipt.js';
import type { ConvertReceipt } from '../../../conversion.js';
import { defaultOutputOperations, outputOperations } from '../../../operations/output.js';
import { outputOperations } from '../../../operations/output.js';

const operation = outputOperations(defaultOutputOperations).convert;
const operation = outputOperations.convert;

export const config = {
annotations: { destructiveHint: true, readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import type { ToolRouteProps } from 'agent-bundle';
import { IdentifyRanking } from '../../../components/candidate-ranking.js';
import { IdentifyTrail } from '../../../components/evidence-trail.js';
import type { AcousticIdentifyReceipt } from '../../../evidence.js';
import { defaultEvidenceOperations, evidenceOperations } from '../../../operations/evidence.js';
import { evidenceOperations } from '../../../operations/evidence.js';

const operation = evidenceOperations(defaultEvidenceOperations).acousticIdentify;
const operation = evidenceOperations.acousticIdentify;

export const config = {
annotations: { openWorldHint: true, readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import type { ToolRouteProps } from 'agent-bundle';

import { InspectionShelf } from '../../../components/library-shelf.js';
import type { InspectionReceipt } from '../../../curator-core.js';
import { defaultDiscoveryOperations, discoveryOperations } from '../../../operations/discovery.js';
import { discoveryOperations } from '../../../operations/discovery.js';

const operation = discoveryOperations(defaultDiscoveryOperations).inspect;
const operation = discoveryOperations.inspect;

export const config = {
annotations: { readOnlyHint: true },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { z } from 'zod';
import { inventoryHeadline } from '../../../components/headlines.js';
import { InventoryShelf } from '../../../components/library-shelf.js';
import type { InventoryReceipt } from '../../../library.js';
import { defaultDiscoveryOperations, discoveryOperations } from '../../../operations/discovery.js';
import { discoveryOperations } from '../../../operations/discovery.js';

const operation = discoveryOperations(defaultDiscoveryOperations).inventory;
const operation = discoveryOperations.inventory;

export const config = {
annotations: { readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import type { ToolRouteProps } from 'agent-bundle';

import { PrepareMutation } from '../../../components/mutation-receipt.js';
import type { PrepareReceipt } from '../../../curator-core.js';
import { defaultOutputOperations, outputOperations } from '../../../operations/output.js';
import { outputOperations } from '../../../operations/output.js';

const operation = outputOperations(defaultOutputOperations).prepare;
const operation = outputOperations.prepare;

export const config = {
annotations: { destructiveHint: true, readOnlyHint: false },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import type { ToolRouteProps } from 'agent-bundle';
import type { AudibleSearchReceipt } from '../../../audible.js';
import { SearchRanking } from '../../../components/candidate-ranking.js';
import { audibleSearchHeadline } from '../../../components/headlines.js';
import { defaultAudibleOperations, audibleOperations } from '../../../operations/audible.js';
import { audibleOperations } from '../../../operations/audible.js';

const operation = audibleOperations(defaultAudibleOperations).audibleSearch;
const operation = audibleOperations.audibleSearch;

export const config = {
annotations: { openWorldHint: true, readOnlyHint: false },
Expand Down
Loading
Loading