UNPKG

aiwg

Version:

Deployment tool and support utility for AI context. Copies agents, skills, commands, rules, and behaviors into the paths each AI platform reads (Claude Code, Codex, Copilot, Cursor, Warp, OpenClaw, and 6 more) so one source of truth works across 10 platfo

393 lines 15.6 kB
/** * Project-Level AIWG Config * * Manages `.aiwg/aiwg.config` — the project-level record of: * - Which AI provider toolchains this project targets * - Which frameworks/addons are deployed (with uninstall metadata) * - User-defined scripts callable via `aiwg run` * * @implements #621 */ import type { ProjectLocalType } from '../extensions/manifest.js'; /** * Artifact counts for one provider deployment */ export interface DeployedArtifactCounts { agents: number; commands: number; skills: number; rules: number; } /** * One entry in the `installed` map */ export interface InstalledEntry { /** Deployed version (CalVer or semver) */ version: string; /** * Source of the deployment: * "bundled" — came from the npm package * "cache" — came from ~/.cache/aiwg/packages/ (#557) * "project-local" — came from .aiwg/{extensions,addons,frameworks,plugins}/<id>/ (#1035) * git URL — direct source URL */ source: 'bundled' | 'cache' | 'project-local' | string; /** ISO-8601 timestamp of last deployment */ installedAt: string; /** Provider → artifact counts */ deployedTo: Record<string, DeployedArtifactCounts>; /** SHA-256 of manifest.json at deploy time; used for stale detection */ manifestHash?: string; /** * Project-local-only fields (set when `source === 'project-local'`). * * Per @.aiwg/architecture/adr-unified-registry-shape.md (ADR companion to * #1035). These three fields MUST be present together when source is * `'project-local'` and SHOULD be absent otherwise. */ /** Path of the bundle directory relative to project root (e.g., ".aiwg/extensions/foo/"). */ localPath?: string; /** Bundle type from the manifest. */ localType?: ProjectLocalType; /** Schema version of the manifest.json this entry was written from (currently `'1'`). */ manifestVersion?: string; /** * Hashes of source artifacts at deploy time, keyed by source-relative path * (e.g., "rules/my-rule.md", "skills/my-skill/SKILL.md"). Used by * `aiwg remove` to detect pristine vs. mutated vs. replaced deployed * files per the design at @.aiwg/architecture/design-aiwg-remove-revert.md. * * Optional — older entries without this field fall back to "always-prompt" * remove behavior until the next `aiwg use` re-records them. * * @implements #1037 */ artifactHashes?: Record<string, string>; } /** * One secondary remote: a mirror, fork base, or publishing target. */ export interface SecondaryRemote { /** Must match a name from `git remote` */ name: string; /** Free-form tag (mirror | upstream | publish | replica | …) */ purpose?: string; /** Hint to release workflows: push tags here on stable cuts */ push_on_release?: boolean; } /** * Repo origin topology — declares which remote is primary (CI / issues / PRs) * and which are secondary (mirrors, publishing targets). * * @implements #994 */ export interface RemotesConfig { /** git remote name driving CI / PRs by default. Defaults to "origin". */ primary?: string; /** Where issues live. Defaults to `primary`. */ issue_tracker?: string; /** Where CI runs. Defaults to `primary`. */ ci?: string; /** Mirrors, fork bases, publishing targets. */ secondary?: SecondaryRemote[]; } /** * Resolved remote topology — every field guaranteed to be set. * Returned by {@link resolveRemotes}. */ export interface ResolvedRemotes { primary: string; issue_tracker: string; ci: string; secondary: SecondaryRemote[]; } /** * Top-level shape of .aiwg/aiwg.config */ export interface AiwgConfig { $schema?: string; version: '1'; /** * AI provider toolchains this project targets. * `aiwg use <framework>` with no --provider flag deploys to ALL of these. */ providers: string[]; /** * Frameworks and addons currently deployed. * Keyed by the name passed to `aiwg use`. */ installed: Record<string, InstalledEntry>; /** * User-defined scripts, run via `aiwg run <name>`. * Executed with `sh -c "<command>"` (or `cmd /c` on Windows). */ scripts: Record<string, string>; /** * Repo origin topology. Optional — when absent, agents treat `origin` as primary. * @implements #994 */ remotes?: RemotesConfig; /** * Repo control / delivery policy — how AIWG agents are expected to ship code. * Optional — when absent, agents fall back to the conservative defaults * applied by `resolveDelivery()`. * @implements #995 */ delivery?: DeliveryConfig; /** * Provider-scoped parallelism caps — limits how many concurrent subagents, * Ralph loops, and Mission Control missions agents may spawn. Composes with * (takes the minimum of) `context-budget` rule caps and `rlm-context-management` * Rule 8's 7-agent hard cap. Optional — when absent, agents fall back to * provider-specific defaults applied by `resolveParallelism()`. * @implements #1359 */ parallelism?: ParallelismConfig; } /** * How agents should ship code — modes: * - `direct` : commit & push straight to default_branch * - `feature-branch` : create a branch and push it, but don't open a PR * - `pr-required` : feature branch + PR via the resolved primary remote */ export type DeliveryMode = 'direct' | 'feature-branch' | 'pr-required'; /** * Merge style preference; matches the values Gitea/GitHub/GitLab APIs accept. */ export type MergeStyle = 'rebase-merge' | 'squash' | 'merge' | 'fast-forward-only'; /** * Force-push policy: * - `never` : agents may never force-push * - `own-branch-only` : OK on the agent's own feature branch, never to main * - `allowed` : escape hatch for tooling that needs it */ export type ForcePushPolicy = 'never' | 'own-branch-only' | 'allowed'; /** * Branch-naming convention. `{issue}` and `{slug}` are interpolated by skills. */ export interface BranchNaming { prefix_by_type?: Partial<Record<'feat' | 'fix' | 'docs' | 'chore' | 'refactor' | 'test', string>>; } /** * Repo control policy — see DeliveryMode for the high-level shape. Every field * is optional; sensible defaults applied via {@link resolveDelivery}. * * @implements #995 */ export interface DeliveryConfig { mode?: DeliveryMode; default_branch?: string; branch_naming?: BranchNaming; merge_style?: MergeStyle; delete_branch_on_merge?: boolean; /** When true, agents must wait for CI green before declaring done. */ require_ci_green?: boolean; require_signed_commits?: boolean; force_push_policy?: ForcePushPolicy; /** Include "Closes #N" / "Fixes #N" in PR body when an issue is referenced. */ auto_close_issues?: boolean; /** Post AL CYCLE status comments to issue threads from address-issues loops. */ issue_comment_on_cycle?: boolean; } /** * Resolved delivery policy with all defaults applied. Returned by * {@link resolveDelivery}. */ export interface ResolvedDelivery { mode: DeliveryMode; default_branch: string; branch_naming: Required<BranchNaming>; merge_style: MergeStyle; delete_branch_on_merge: boolean; require_ci_green: boolean; require_signed_commits: boolean; force_push_policy: ForcePushPolicy; auto_close_issues: boolean; issue_comment_on_cycle: boolean; } /** * Resolve the delivery policy with defaults applied. * * Defaults are intentionally conservative — they match what AIWG agents * naturally do today (PR-required, rebase-merge, no force pushes, post issue * comments) so that adding the schema doesn't shift behavior for existing * projects. */ export declare function resolveDelivery(delivery: DeliveryConfig | undefined): ResolvedDelivery; /** * Provider-scoped parallelism cap — limits how many concurrent subagents, * Ralph loops, and Mission Control missions agents may spawn. Designed to * keep AIWG within the rate-limit envelope of the underlying model provider * (Anthropic per-key TPM/RPM caps are the most-reported trigger). * * Composes with (effective limit = MIN of): * - `parallelism.max_parallel_subagents` (this config) * - `context-budget` rule's `AIWG_CONTEXT_WINDOW`-derived cap, if set * - `rlm-context-management` Rule 8's 7-agent hard cap (RLM dispatches only) * - The natural task decomposition (no point spawning 4 when only 2 subtasks exist) * * Every field is optional. Defaults applied via {@link resolveParallelism}. * * @implements #1359 */ export interface ParallelismConfig { /** Max concurrent subagents (Task dispatches, rlm-batch fan-outs). */ max_parallel_subagents?: number; /** Max concurrent Ralph external loops (`aiwg agent-loop-ext`). */ max_parallel_ralph_loops?: number; /** Max concurrent Mission Control missions (`aiwg mc dispatch`). */ max_parallel_mc_missions?: number; /** Free-form note explaining why this cap was chosen (e.g., plan tier). */ rationale?: string; } /** * Resolved parallelism caps with all defaults applied. Returned by * {@link resolveParallelism}. */ export interface ResolvedParallelism { max_parallel_subagents: number; max_parallel_ralph_loops: number; max_parallel_mc_missions: number; rationale?: string; } /** * Per-provider parallelism defaults. Conservative numbers for Anthropic-backed * providers reflect Pro/Team-plan rate limits — operators on Enterprise tiers * should bump via `aiwg config set --project parallelism.max_parallel_subagents N`. * * Sources for the numbers: * - claude / claude-code: Anthropic per-key throttling at higher concurrency * - codex / copilot / etc.: OpenAI / GitHub quotas are generally per-org and * less aggressive at small fan-outs (10 is a safe middle ground) * - hermes: MCP sidecar; rate-limit depends on upstream provider, operator * should tune. Conservative 10 default. * - unknown: conservative 4 default. */ export declare const PROVIDER_PARALLELISM_DEFAULTS: Record<string, ResolvedParallelism>; /** * Return the provider's parallelism defaults, or the conservative fallback * when the provider is unknown. */ export declare function getProviderParallelismDefaults(provider: string | undefined): ResolvedParallelism; /** * Resolve the parallelism caps with provider-aware defaults applied. The * primary provider drives the default — typically the first entry in the * project's `providers` array. * * When `parallelism` has explicit values, they override the provider default * field-by-field. When no provider is supplied (or it's not in the defaults * map), the conservative 4-subagent fallback applies. * * @implements #1359 */ export declare function resolveParallelism(parallelism: ParallelismConfig | undefined, primaryProvider?: string): ResolvedParallelism; /** * Provider tag for a given remote URL. Used by skills (issue-create, * pr-review, commit-and-push) to pick the right CLI / MCP client when * the operator didn't pass `--provider` explicitly. * * Recognized hosts: * - github.com → 'github' * - gitlab.com / gitlab.* → 'gitlab' * - any host containing 'gitea' (or matching the typical Gitea path shape) → 'gitea' * * Returns 'unknown' for self-hosted instances we can't classify by host alone — * callers should then prompt the operator or fall back to the configured * AIWG provider list. * * @implements #997 */ export declare function resolveRemoteProvider(remoteUrl: string): 'github' | 'gitlab' | 'gitea' | 'unknown'; /** * Resolve the repo remote topology with defaults applied. * * Defaults: * - `primary` defaults to "origin" * - `issue_tracker` defaults to `primary` * - `ci` defaults to `primary` * - `secondary` defaults to `[]` * * Pass an absent or partial `remotes` block — every field comes back populated. */ export declare function resolveRemotes(remotes: RemotesConfig | undefined): ResolvedRemotes; /** * Valid provider names (mirrors PROVIDER_PATHS in use.ts) */ export declare const VALID_PROVIDERS: readonly ["claude", "factory", "codex", "opencode", "copilot", "cursor", "warp", "windsurf", "hermes", "openclaw"]; export type Provider = typeof VALID_PROVIDERS[number]; /** * Empty config template. * * Includes an explicit `delivery` block defaulting to `pr-required`. The * runtime default in {@link resolveDelivery} is the same, so this is purely * for visibility — new projects ship with the policy written down so users * can see what their agents will do, and switch via `aiwg config set` or * the AIWG Steward agent without first having to discover the field exists. */ export declare function emptyConfig(providers?: string[]): AiwgConfig; /** * Resolve path to .aiwg/aiwg.config for a project directory */ export declare function getConfigPath(projectDir: string): string; /** * Resolve the project directory for a handler invocation. * * Precedence: * 1. `--target <path>` or `--prefix <path>` flag in args * 2. The HandlerContext `cwd`, if provided * 3. `process.cwd()` * * All three variants existed scattered across handlers (#919 cleanup). * Use this helper so we have one authoritative resolution. */ export declare function getProjectDir(ctx: { cwd?: string; } | undefined, args?: readonly string[]): string; /** * Read .aiwg/aiwg.config. * Returns null if the file does not exist. */ export declare function readAiwgConfig(projectDir: string): Promise<AiwgConfig | null>; /** * Write .aiwg/aiwg.config, creating .aiwg/ if needed. */ export declare function writeAiwgConfig(projectDir: string, config: AiwgConfig): Promise<void>; /** * Update the `installed` record for a framework after a successful deployment. * Returns the updated config (does not write to disk — caller must call writeAiwgConfig). */ export declare function updateInstalled(config: AiwgConfig, name: string, provider: string, counts: DeployedArtifactCounts, opts: { version: string; source: string; manifestHash?: string; /** Set when source === 'project-local'. Relative to project root. */ localPath?: string; /** Set when source === 'project-local'. */ localType?: ProjectLocalType; /** Set when source === 'project-local'. */ manifestVersion?: string; /** Optional source-artifact hash map for project-local remove revert (#1037). */ artifactHashes?: Record<string, string>; }): AiwgConfig; /** * Aggregate deployment counts across all installed frameworks for a given provider. * Returns the totals for agents, commands, skills, and rules. * If no provider is specified, uses the first configured provider. */ export declare function getDeploymentSummary(config: AiwgConfig, provider?: string): DeployedArtifactCounts; /** * Compute SHA-256 hash of a manifest.json file. * Returns undefined if the file cannot be read. */ export declare function hashManifest(manifestPath: string): Promise<string | undefined>; /** * Scan actual deployment directories and populate `deployedTo` for any * `installed` entries that have an empty `deployedTo` map. * * Called by `aiwg init` when migrating a project that already has frameworks * deployed but whose config was created before deployment-tracking was added. * * @implements #721 */ export declare function populateDeployedTo(config: AiwgConfig, projectDir: string): Promise<AiwgConfig>; //# sourceMappingURL=aiwg-config.d.ts.map