{"version":3,"file":"forge.mjs","names":[],"sources":["../../../src/batteries/dev_tools/forge.ts"],"sourcesContent":["/** Agent glue for the structured development-tools surface. @module @nhtio/adk/batteries/dev-tools/forge */\nimport { DEV_ARG_SPECS } from './arg_specs'\nimport { validator } from '@nhtio/validation'\nimport { Tool, SpooledJsonArtifact } from '@nhtio/adk/common'\nimport type { DevOp, DevPipeline } from './types'\nimport type { DispatchContext } from '@nhtio/adk/types'\n\n/** Configuration for {@link forgeDevTools}. The pipeline owns approval; the forge never gates. */\nexport interface ForgeDevToolsOptions {\n  /** Select the single composite tool or the stateless per-step tools. */\n  surface: 'composite' | 'granular'\n  /** Optional names and descriptions keyed by their default tool name. */\n  overrides?: Record<string, { name?: string; description?: string }>\n}\n\nconst stepSchema = (step: string, includePaths: boolean) => {\n  const shape: Record<string, ReturnType<typeof validator.any>> = {}\n  if (includePaths)\n    shape.paths = validator\n      .array()\n      .items(validator.string())\n      .required()\n      .description('Workspace-relative paths or glob patterns to acquire.')\n  for (const [name, rule] of Object.entries(DEV_ARG_SPECS[step] ?? {})) {\n    let field: ReturnType<typeof validator.any>\n    if (rule.type === 'string') field = validator.string()\n    else if (rule.type === 'number') field = validator.number()\n    else if (rule.type === 'boolean') field = validator.boolean()\n    else if (rule.element === 'string') field = validator.array().items(validator.string())\n    else if (typeof rule.element === 'object') {\n      const fields: Record<string, ReturnType<typeof validator.any>> = {}\n      for (const [key, spec] of Object.entries(rule.element.fields)) {\n        const actual = typeof spec === 'string' ? { type: spec } : spec\n        fields[key] = actual.type === 'string' ? validator.string() : validator.any().required()\n        fields[key] = fields[key].required()\n      }\n      field = validator.array().items(validator.object(fields))\n    } else field = validator.array()\n    if (rule.required) field = field.required()\n    shape[name] = field\n  }\n  return validator.object(shape)\n}\n\nconst render = (result: Awaited<ReturnType<DevPipeline['ops']>>) => JSON.stringify(result, null, 2)\nconst opArgs = (args: Record<string, unknown>): Record<string, unknown> => {\n  const { paths: omittedPaths, ...rest } = args\n  void omittedPaths\n  return Object.fromEntries(Object.entries(rest).filter(([, value]) => value !== undefined))\n}\n\n/** Forge model-facing tools over a configured development pipeline. */\nexport const forgeDevTools = (\n  pipeline: DevPipeline,\n  options: ForgeDevToolsOptions\n): Record<string, Tool> => {\n  if (options?.surface !== 'composite' && options?.surface !== 'granular')\n    throw new Error(\"forgeDevTools requires surface: 'composite' | 'granular'\")\n  const tools: Record<string, Tool> = {}\n  const make = (\n    defaultName: string,\n    description: string,\n    schema: ReturnType<typeof validator.object>,\n    handler: (args: Record<string, unknown>, context: DispatchContext) => Promise<string>\n  ) => {\n    const override = options.overrides?.[defaultName]\n    const tool = new Tool({\n      name: override?.name ?? defaultName,\n      description: override?.description ?? description,\n      inputSchema: schema,\n      artifactConstructor: () => SpooledJsonArtifact,\n      handler: async (args, context) =>\n        handler(args as Record<string, unknown>, context as DispatchContext),\n    })\n    tools[tool.name] = tool\n  }\n  if (options.surface === 'composite') {\n    make(\n      'dev_plan',\n      'Run a multi-step development editing plan. Prefer this tool for workflows with more than one step.',\n      validator.object({\n        paths: validator.array().items(validator.string()).required(),\n        ops: validator\n          .array()\n          .items(\n            validator.object({\n              step: validator.string().required(),\n              args: validator.object({}).unknown(true).required(),\n              label: validator.string(),\n            })\n          )\n          .min(1)\n          .required(),\n      }),\n      async (args, context) =>\n        render(\n          await pipeline.ops(args.paths as string[], args.ops as DevOp[], {\n            signal: context.abortSignal,\n          })\n        )\n    )\n    return tools\n  }\n  for (const step of Object.keys(DEV_ARG_SPECS)) {\n    if (step === 'write') continue\n    make(\n      step,\n      `${step} over newly acquired workspace paths. This stateless granular tool persists mutations before returning; use dev_plan for multi-step work.`,\n      stepSchema(step, true),\n      async (args, context) => {\n        const run = (\n          pipeline as DevPipeline & {\n            _runGranular?: (\n              paths: readonly string[],\n              ops: DevOp[],\n              options?: { signal?: AbortSignal }\n            ) => Promise<Awaited<ReturnType<DevPipeline['ops']>>>\n          }\n        )._runGranular\n        const result = run\n          ? await run(args.paths as string[], [{ step, args: opArgs(args) }], {\n              signal: context.abortSignal,\n            })\n          : await pipeline.ops(args.paths as string[], [{ step, args: opArgs(args) }], {\n              signal: context.abortSignal,\n            })\n        return render(result)\n      }\n    )\n  }\n  return tools\n}\n"],"mappings":"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"}