specrails-core 5.2.3 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/bin/specrails-core.mjs +5 -0
- package/dist/agent-runtime/cli-executor.d.ts +34 -0
- package/dist/agent-runtime/cli-executor.js +335 -0
- package/dist/agent-runtime/cli-executor.js.map +1 -0
- package/dist/agent-runtime/cli-process.d.ts +32 -0
- package/dist/agent-runtime/cli-process.js +159 -0
- package/dist/agent-runtime/cli-process.js.map +1 -0
- package/dist/agent-runtime/cli.d.ts +38 -0
- package/dist/agent-runtime/cli.js +168 -0
- package/dist/agent-runtime/cli.js.map +1 -0
- package/dist/agent-runtime/config.d.ts +7 -0
- package/dist/agent-runtime/config.js +162 -0
- package/dist/agent-runtime/config.js.map +1 -0
- package/dist/agent-runtime/core-host.d.ts +33 -0
- package/dist/agent-runtime/core-host.js +97 -0
- package/dist/agent-runtime/core-host.js.map +1 -0
- package/dist/agent-runtime/durable-store.d.ts +22 -0
- package/dist/agent-runtime/durable-store.js +205 -0
- package/dist/agent-runtime/durable-store.js.map +1 -0
- package/dist/agent-runtime/executor-types.d.ts +92 -0
- package/dist/agent-runtime/executor-types.js +29 -0
- package/dist/agent-runtime/executor-types.js.map +1 -0
- package/dist/agent-runtime/executors.d.ts +22 -0
- package/dist/agent-runtime/executors.js +44 -0
- package/dist/agent-runtime/executors.js.map +1 -0
- package/dist/agent-runtime/gemini-policy.d.ts +8 -0
- package/dist/agent-runtime/gemini-policy.js +36 -0
- package/dist/agent-runtime/gemini-policy.js.map +1 -0
- package/dist/agent-runtime/graph/artifacts.d.ts +40 -0
- package/dist/agent-runtime/graph/artifacts.js +179 -0
- package/dist/agent-runtime/graph/artifacts.js.map +1 -0
- package/dist/agent-runtime/graph/nodes.d.ts +36 -0
- package/dist/agent-runtime/graph/nodes.js +274 -0
- package/dist/agent-runtime/graph/nodes.js.map +1 -0
- package/dist/agent-runtime/graph/review-policy.d.ts +18 -0
- package/dist/agent-runtime/graph/review-policy.js +32 -0
- package/dist/agent-runtime/graph/review-policy.js.map +1 -0
- package/dist/agent-runtime/graph/roles.d.ts +44 -0
- package/dist/agent-runtime/graph/roles.js +126 -0
- package/dist/agent-runtime/graph/roles.js.map +1 -0
- package/dist/agent-runtime/graph/state.d.ts +75 -0
- package/dist/agent-runtime/graph/state.js +23 -0
- package/dist/agent-runtime/graph/state.js.map +1 -0
- package/dist/agent-runtime/graph-checkpointer.d.ts +61 -0
- package/dist/agent-runtime/graph-checkpointer.js +137 -0
- package/dist/agent-runtime/graph-checkpointer.js.map +1 -0
- package/dist/agent-runtime/index.d.ts +14 -0
- package/dist/agent-runtime/index.js +15 -0
- package/dist/agent-runtime/index.js.map +1 -0
- package/dist/agent-runtime/kimi-acp.d.ts +7 -0
- package/dist/agent-runtime/kimi-acp.js +179 -0
- package/dist/agent-runtime/kimi-acp.js.map +1 -0
- package/dist/agent-runtime/openai-executor.d.ts +18 -0
- package/dist/agent-runtime/openai-executor.js +174 -0
- package/dist/agent-runtime/openai-executor.js.map +1 -0
- package/dist/agent-runtime/prompts.d.ts +40 -0
- package/dist/agent-runtime/prompts.js +291 -0
- package/dist/agent-runtime/prompts.js.map +1 -0
- package/dist/agent-runtime/workflow-types.d.ts +210 -0
- package/dist/agent-runtime/workflow-types.js +2 -0
- package/dist/agent-runtime/workflow-types.js.map +1 -0
- package/dist/agent-runtime/workflow.d.ts +17 -0
- package/dist/agent-runtime/workflow.js +609 -0
- package/dist/agent-runtime/workflow.js.map +1 -0
- package/dist/agent-runtime/workspace-tools.d.ts +25 -0
- package/dist/agent-runtime/workspace-tools.js +120 -0
- package/dist/agent-runtime/workspace-tools.js.map +1 -0
- package/dist/installer/cli.d.ts +35 -0
- package/dist/installer/cli.js +3 -0
- package/dist/installer/cli.js.map +1 -1
- package/dist/installer/commands/doctor.d.ts +27 -0
- package/dist/installer/commands/framework.d.ts +85 -0
- package/dist/installer/commands/init.d.ts +147 -0
- package/dist/installer/commands/update.d.ts +56 -0
- package/dist/installer/commands/v5-migration.d.ts +32 -0
- package/dist/installer/phases/framework-lifecycle.d.ts +53 -0
- package/dist/installer/phases/install-config.d.ts +64 -0
- package/dist/installer/phases/manifest.d.ts +45 -0
- package/dist/installer/phases/prereqs.d.ts +51 -0
- package/dist/installer/phases/provider-detect.d.ts +89 -0
- package/dist/installer/phases/scaffold.d.ts +211 -0
- package/dist/installer/runtime/kimi.d.ts +84 -0
- package/dist/installer/runtime/pipeline-state.d.ts +210 -0
- package/dist/installer/runtime/pipeline-state.js +46 -22
- package/dist/installer/runtime/pipeline-state.js.map +1 -1
- package/dist/installer/util/errors.d.ts +46 -0
- package/dist/installer/util/exec.d.ts +41 -0
- package/dist/installer/util/fs.d.ts +153 -0
- package/dist/installer/util/git.d.ts +44 -0
- package/dist/installer/util/install-transaction.d.ts +29 -0
- package/dist/installer/util/logger.d.ts +31 -0
- package/dist/installer/util/paths.d.ts +34 -0
- package/dist/installer/util/prompts.d.ts +23 -0
- package/dist/installer/util/registry.d.ts +174 -0
- package/dist/installer/util/template.d.ts +23 -0
- package/docs/README.md +1 -0
- package/docs/agent-runtime.md +268 -0
- package/integration-contract.json +79 -7
- package/package.json +16 -1
- package/schemas/agent-runtime.schema.json +55 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface V5MigrationInput {
|
|
2
|
+
/** Absolute artifact root (in-repo repoRoot, or the relocated $HOME workspace). */
|
|
3
|
+
artifactRoot: string;
|
|
4
|
+
/** Provider directory name (`.claude` / `.codex` / `.gemini`). */
|
|
5
|
+
providerDir: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Removes artefacts a pre-v5 install left behind so the fresh v5 template set
|
|
9
|
+
* places into a clean tree. Strictly subtractive and reserved-path-safe:
|
|
10
|
+
*
|
|
11
|
+
* - Removed agent files (`.claude/agents/sr-*.md`, `.gemini/agents/sr-*.md`)
|
|
12
|
+
* - Removed command files (`<providerDir>/commands/specrails/*.md`) and their
|
|
13
|
+
* codex skill dirs (`.codex/skills/<cmd>/`)
|
|
14
|
+
* - The generated top-level skills for removed commands (`.claude/skills/<id>/`)
|
|
15
|
+
* - Obsolete staging subtrees under `.specrails/setup-templates/`
|
|
16
|
+
* (`personas/`, `skills/enrich/`, and the removed command/agent templates)
|
|
17
|
+
* - VPC persona output dirs (`<providerDir>/agents/personas/`)
|
|
18
|
+
*
|
|
19
|
+
* `custom-*.md` agents and `.specrails/profiles/**` are protected by
|
|
20
|
+
* {@link isReservedPath}; files the installer never owned are not enumerated
|
|
21
|
+
* here, so they are untouched. When at least one path is removed a migration
|
|
22
|
+
* summary is printed so the user sees exactly what changed.
|
|
23
|
+
*/
|
|
24
|
+
export declare function migratePreV5Install(input: V5MigrationInput): void;
|
|
25
|
+
/**
|
|
26
|
+
* Test helper: enumerate removed agent/command ids so specs can assert the
|
|
27
|
+
* migration set stays in lock-step with the deleted templates.
|
|
28
|
+
*/
|
|
29
|
+
export declare const V5_REMOVED: {
|
|
30
|
+
readonly agents: readonly ["sr-product-manager", "sr-product-analyst", "sr-test-writer", "sr-doc-sync", "sr-merge-resolver", "sr-frontend-developer", "sr-backend-developer", "sr-frontend-reviewer", "sr-backend-reviewer", "sr-security-reviewer", "sr-performance-reviewer"];
|
|
31
|
+
readonly commands: readonly ["enrich", "reconfig", "vpc-drift", "auto-propose-backlog-specs", "get-backlog-specs", "merge-resolve", "test"];
|
|
32
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type Provider } from './provider-detect.js';
|
|
2
|
+
/**
|
|
3
|
+
* Stable provider order for the global framework store. `framework/current` is
|
|
4
|
+
* shared by every relocated workspace, so a version transition must carry
|
|
5
|
+
* forward every provider that can still have live links through that pointer.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FRAMEWORK_PROVIDERS: readonly Provider[];
|
|
8
|
+
export interface ResolveRequiredFrameworkProvidersInput {
|
|
9
|
+
frameworkDir: string;
|
|
10
|
+
/** Providers requested by the lifecycle operation that is about to swap. */
|
|
11
|
+
requested?: readonly Provider[];
|
|
12
|
+
/** Registry home. Defaults to SPECRAILS_REGISTRY_HOME / the normal home. */
|
|
13
|
+
registryHome?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface MaterializeFrameworkVersionInput extends ResolveRequiredFrameworkProvidersInput {
|
|
16
|
+
scriptDir: string;
|
|
17
|
+
version: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Discover providers represented by a framework version.
|
|
21
|
+
*
|
|
22
|
+
* A provider is included when either its subtree or its stamp exists. For the
|
|
23
|
+
* current version this is deliberately conservative: an interrupted/legacy
|
|
24
|
+
* materialization without a stamp may still have live workspace symlinks, so
|
|
25
|
+
* the next version must carry that provider forward rather than dropping it.
|
|
26
|
+
*/
|
|
27
|
+
export declare function discoverFrameworkProviders(frameworkDir: string, version: string): Provider[];
|
|
28
|
+
/**
|
|
29
|
+
* Compute the provider set that MUST exist in a destination version before the
|
|
30
|
+
* process may move the global `current` pointer:
|
|
31
|
+
*
|
|
32
|
+
* 1. providers requested by this operation;
|
|
33
|
+
* 2. every supported provider recorded by any project in registry.json;
|
|
34
|
+
* 3. every provider represented by the version currently serving workspaces.
|
|
35
|
+
*
|
|
36
|
+
* Taking the global registry union (not just the active project) is essential:
|
|
37
|
+
* `framework/current` is global, while provider inventories are per project.
|
|
38
|
+
*/
|
|
39
|
+
export declare function resolveRequiredFrameworkProviders(input: ResolveRequiredFrameworkProvidersInput): Provider[];
|
|
40
|
+
/**
|
|
41
|
+
* Fail closed when a destination version is missing or only partially
|
|
42
|
+
* materialized. A valid provider requires BOTH its provider subtree and the
|
|
43
|
+
* final stamp written after scaffold completion, with matching version/provider
|
|
44
|
+
* fields. The caller may supply an empty requirement only for a first install;
|
|
45
|
+
* in that case at least one complete provider must be discoverable in target.
|
|
46
|
+
*/
|
|
47
|
+
export declare function assertFrameworkVersionComplete(frameworkDir: string, version: string, requiredProviders: readonly Provider[]): Provider[];
|
|
48
|
+
/**
|
|
49
|
+
* Materialize a complete destination version and expose it with ONE atomic
|
|
50
|
+
* pointer swap. No call in the provider loop can move `current`; if any provider
|
|
51
|
+
* fails, existing workspaces continue resolving through the previous version.
|
|
52
|
+
*/
|
|
53
|
+
export declare function materializeFrameworkVersion(input: MaterializeFrameworkVersionInput): Provider[];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { InstallerError } from '../util/errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Provider identifier. Kept in lock-step with `provider-detect.ts` `Provider`.
|
|
4
|
+
*/
|
|
5
|
+
export type Provider = 'claude' | 'codex' | 'gemini' | 'kimi';
|
|
6
|
+
/** Cost / capability preset for the model picker. */
|
|
7
|
+
export type ModelPreset = 'balanced' | 'budget' | 'max';
|
|
8
|
+
/** Provider-native model selection retained verbatim in install-config.yaml. */
|
|
9
|
+
export interface InstallModelConfig {
|
|
10
|
+
preset: ModelPreset;
|
|
11
|
+
defaults: {
|
|
12
|
+
model: string;
|
|
13
|
+
};
|
|
14
|
+
overrides: Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Shape of the `.specrails/install-config.yaml` file — the single
|
|
18
|
+
* source of truth the TUI writes and the installer reads. Fields map
|
|
19
|
+
* 1:1 onto the grep-based parser in the retired install.sh.
|
|
20
|
+
*/
|
|
21
|
+
export interface InstallConfig {
|
|
22
|
+
version: 1;
|
|
23
|
+
provider: Provider;
|
|
24
|
+
agents: {
|
|
25
|
+
selected: string[];
|
|
26
|
+
excluded?: string[];
|
|
27
|
+
/** Legacy pre-models-section location, accepted for backward compatibility. */
|
|
28
|
+
preset?: ModelPreset;
|
|
29
|
+
};
|
|
30
|
+
models?: InstallModelConfig;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve a preset into provider-native identifiers. Kimi currently exposes no
|
|
34
|
+
* Core-defined cost/capability tier mapping, so every named preset resolves to
|
|
35
|
+
* its explicit `k3` default. User-supplied exact identifiers are handled later
|
|
36
|
+
* and are never interpreted as Claude aliases.
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveProviderModelConfig(provider: Provider, preset?: ModelPreset): InstallModelConfig;
|
|
39
|
+
export declare class InvalidConfigError extends InstallerError {
|
|
40
|
+
readonly errors: string[];
|
|
41
|
+
constructor(errors: string[]);
|
|
42
|
+
}
|
|
43
|
+
export declare const CONFIG_RELATIVE_PATH = ".specrails/install-config.yaml";
|
|
44
|
+
/**
|
|
45
|
+
* Resolves the install-config path: explicit argument > repo-root default.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveConfigPath(repoRoot: string, explicit?: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Reads and parses the install-config. Returns `null` if the file is
|
|
50
|
+
* not present — caller decides whether that's an error or a fallback.
|
|
51
|
+
*/
|
|
52
|
+
export declare function loadInstallConfig(configPath: string): InstallConfig | null;
|
|
53
|
+
/**
|
|
54
|
+
* Validates an already-parsed YAML document. Collects every error
|
|
55
|
+
* before throwing so the user sees them all at once (matches the
|
|
56
|
+
* bash installer's `_config_errors` accumulator behaviour).
|
|
57
|
+
*/
|
|
58
|
+
export declare function validateInstallConfig(raw: unknown): InstallConfig;
|
|
59
|
+
/**
|
|
60
|
+
* Serialises an {@link InstallConfig} back to YAML and writes it with
|
|
61
|
+
* LF line endings. Used by `npx specrails-core update --reset-config`
|
|
62
|
+
* paths (not wired yet) and by tests.
|
|
63
|
+
*/
|
|
64
|
+
export declare function writeInstallConfig(configPath: string, config: InstallConfig): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape of the `.specrails/specrails-manifest.json` file the installer
|
|
3
|
+
* writes at install time. Consumers (specrails-desktop's compat check,
|
|
4
|
+
* the `doctor` command, update.sh) parse it to detect template drift.
|
|
5
|
+
*/
|
|
6
|
+
export interface SpecrailsManifest {
|
|
7
|
+
version: string;
|
|
8
|
+
installed_at: string;
|
|
9
|
+
/** Provider inventory is emitted only by provider-aware lifecycle callers. */
|
|
10
|
+
providers?: string[];
|
|
11
|
+
primary_provider?: string;
|
|
12
|
+
artifacts: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Computes a stable sha256 digest for a file, returned as `sha256:<hex>`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function sha256Of(filePath: string): string;
|
|
18
|
+
export interface BuildManifestInput {
|
|
19
|
+
/** Absolute path to the specrails-core source package directory. */
|
|
20
|
+
scriptDir: string;
|
|
21
|
+
/** Absolute path to the user's repo root where the manifest is written. */
|
|
22
|
+
repoRoot: string;
|
|
23
|
+
/** Version string from the specrails-core VERSION file. */
|
|
24
|
+
version: string;
|
|
25
|
+
/** Override "installed_at" — exposed for deterministic testing. */
|
|
26
|
+
installedAt?: string;
|
|
27
|
+
/** Provider(s) materialized by this lifecycle pass. Existing entries are unioned. */
|
|
28
|
+
providers?: string[];
|
|
29
|
+
primaryProvider?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Walks `templates/**` plus the bundled doctor command file and
|
|
33
|
+
* produces a stable-sorted manifest.
|
|
34
|
+
*
|
|
35
|
+
* Stable-sort rule: artifact keys are sorted ascending by POSIX path.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildManifest(input: BuildManifestInput): SpecrailsManifest;
|
|
38
|
+
/**
|
|
39
|
+
* Writes the manifest JSON and the companion version file under
|
|
40
|
+
* `.specrails/` in the user repo. Both files use LF terminators.
|
|
41
|
+
*/
|
|
42
|
+
export declare function writeManifestFiles(repoRoot: string, manifest: SpecrailsManifest): {
|
|
43
|
+
manifestPath: string;
|
|
44
|
+
versionPath: string;
|
|
45
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type Provider, type ProviderAvailability } from './provider-detect.js';
|
|
2
|
+
/**
|
|
3
|
+
* OpenSpec 1.4.1, which the installer invokes during the default init/update
|
|
4
|
+
* flow, requires Node >=20.19.0. Keep this floor independent from Kimi's npm
|
|
5
|
+
* package requirement: SpecRails launches an externally installed Kimi CLI and
|
|
6
|
+
* does not require the Kimi npm distribution.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MIN_NODE_VERSION = "20.19.0";
|
|
9
|
+
export declare function isSupportedNodeVersion(version: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Phase 1 prerequisite bundle. Mirrors install.sh's Phase 1 flow but
|
|
12
|
+
* with explicit options rather than a grab-bag of globals.
|
|
13
|
+
*
|
|
14
|
+
* Returns the resolved inputs later phases need — primarily the
|
|
15
|
+
* selected provider and the detected CLI availability.
|
|
16
|
+
*/
|
|
17
|
+
export interface PrereqOptions {
|
|
18
|
+
/** Absolute path to the target repository root. */
|
|
19
|
+
repoRoot: string;
|
|
20
|
+
/** --yes / -y equivalent — auto-init git, skip interactive prompts. */
|
|
21
|
+
autoYes: boolean;
|
|
22
|
+
/** Explicit --provider flag (if passed). */
|
|
23
|
+
explicitProvider?: Provider;
|
|
24
|
+
/** SPECRAILS_SKIP_PREREQS=1 equivalent — relax hard failures for CI. */
|
|
25
|
+
skipPrereqs: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface PrereqResult {
|
|
28
|
+
availability: ProviderAvailability;
|
|
29
|
+
provider: Provider;
|
|
30
|
+
/**
|
|
31
|
+
* OSS heuristics. Three signals must align for `isOss` to be true:
|
|
32
|
+
* a public GitHub repo (via `gh repo view`), at least one CI workflow
|
|
33
|
+
* file under `.github/workflows/`, and a `CONTRIBUTING.md` at the
|
|
34
|
+
* repo root or under `.github/`. Surfaced for downstream tooling that
|
|
35
|
+
* wants to tailor behaviour to open-source projects.
|
|
36
|
+
*/
|
|
37
|
+
ossSignals: OssSignals;
|
|
38
|
+
}
|
|
39
|
+
export interface OssSignals {
|
|
40
|
+
hasGh: boolean;
|
|
41
|
+
publicRepo: boolean;
|
|
42
|
+
hasCi: boolean;
|
|
43
|
+
hasContributing: boolean;
|
|
44
|
+
isOss: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Orchestrates every prerequisite check that must pass before the
|
|
48
|
+
* installer proceeds to Phase 3 (scaffolding). Emits ok/warn/info
|
|
49
|
+
* lines matching the retired bash output.
|
|
50
|
+
*/
|
|
51
|
+
export declare function checkPrerequisites(options: PrereqOptions): Promise<PrereqResult>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider detection + authentication checks. These mirror the Phase
|
|
3
|
+
* 1.2 / 1.3 branches of the retired install.sh.
|
|
4
|
+
*/
|
|
5
|
+
export type Provider = 'claude' | 'codex' | 'gemini' | 'kimi';
|
|
6
|
+
/** Oldest TypeScript Kimi Code CLI release covered by this integration. */
|
|
7
|
+
export declare const MIN_KIMI_VERSION = "0.27.0";
|
|
8
|
+
export interface ProviderAvailability {
|
|
9
|
+
claude: boolean;
|
|
10
|
+
codex: boolean;
|
|
11
|
+
/** Optional so callers/tests predating Gemini still typecheck; absent = false. */
|
|
12
|
+
gemini?: boolean;
|
|
13
|
+
/** Optional so callers/tests predating Kimi still typecheck; absent = false. */
|
|
14
|
+
kimi?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface ProviderDerivedPaths {
|
|
17
|
+
/** Root directory inside the user's repo: `.claude` / `.codex` / `.gemini` / `.kimi-code`. */
|
|
18
|
+
providerDir: string;
|
|
19
|
+
/** Instructions file relative to the artifact root. */
|
|
20
|
+
instructionsFile: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Detects which AI CLIs are on PATH. Runs `where` on Windows and
|
|
24
|
+
* `which` on POSIX via the cross-platform commandExists helper.
|
|
25
|
+
*/
|
|
26
|
+
export declare function detectAvailability(): Promise<ProviderAvailability>;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the Claude CLI version string (stdout of `claude --version`)
|
|
29
|
+
* or 'unknown' if the CLI cannot be invoked.
|
|
30
|
+
*/
|
|
31
|
+
export declare function claudeVersion(): Promise<string>;
|
|
32
|
+
/** Returns the raw Kimi Code CLI version or `unknown` when it cannot be probed. */
|
|
33
|
+
export declare function kimiVersion(): Promise<string>;
|
|
34
|
+
/** Extracts a semver-like triple from version output such as `kimi-code 0.27.0`. */
|
|
35
|
+
export declare function parseCliVersion(raw: string): string | null;
|
|
36
|
+
/** True when `raw` identifies a Kimi CLI at or above {@link MIN_KIMI_VERSION}. */
|
|
37
|
+
export declare function isSupportedKimiVersion(raw: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Resolves which provider the installer should use. Priority:
|
|
40
|
+
* 1. Explicit `--provider claude` flag (already passed through args).
|
|
41
|
+
* 2. Config file (read upstream in install-config.ts).
|
|
42
|
+
* 3. Whichever CLI is installed.
|
|
43
|
+
*
|
|
44
|
+
* The caller may bypass prereq failures with `skipPrereqs: true`
|
|
45
|
+
* (env `SPECRAILS_SKIP_PREREQS=1`).
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveProvider(availability: ProviderAvailability, options?: {
|
|
48
|
+
explicit?: Provider;
|
|
49
|
+
skipPrereqs?: boolean;
|
|
50
|
+
}): Promise<Provider>;
|
|
51
|
+
/**
|
|
52
|
+
* Directory / filename conventions the provider dictates.
|
|
53
|
+
* - Claude Code: .claude/ + CLAUDE.md
|
|
54
|
+
* - Codex: .codex/ + AGENTS.md
|
|
55
|
+
* - Gemini CLI: .gemini/ + GEMINI.md
|
|
56
|
+
* - Kimi Code: .kimi-code/ + AGENTS.md
|
|
57
|
+
*/
|
|
58
|
+
export declare function derivedPaths(provider: Provider): ProviderDerivedPaths;
|
|
59
|
+
/**
|
|
60
|
+
* Asserts that Claude Code is authenticated. Matches the three-path
|
|
61
|
+
* check from install.sh: `claude config list` → ANTHROPIC_API_KEY env →
|
|
62
|
+
* ~/.claude.json OAuth.
|
|
63
|
+
*/
|
|
64
|
+
export declare function assertClaudeAuthenticated(options?: {
|
|
65
|
+
skipPrereqs?: boolean;
|
|
66
|
+
}): Promise<void>;
|
|
67
|
+
export type KimiAuthenticationStatus = 'authenticated' | 'unauthenticated' | 'unknown';
|
|
68
|
+
/**
|
|
69
|
+
* Bounded, non-billing Kimi authentication probe.
|
|
70
|
+
*
|
|
71
|
+
* Kimi 0.27 has no CLI command that proves managed OAuth readiness without
|
|
72
|
+
* starting a model request. We therefore recognise non-secret evidence (the
|
|
73
|
+
* managed credential file or a process-scoped model key), and honour explicit
|
|
74
|
+
* login failures emitted by `kimi doctor`. A successful `kimi doctor` only
|
|
75
|
+
* validates configuration, so it deliberately yields `unknown`.
|
|
76
|
+
*/
|
|
77
|
+
export declare function probeKimiAuthentication(options?: {
|
|
78
|
+
kimiCodeHome?: string;
|
|
79
|
+
env?: NodeJS.ProcessEnv;
|
|
80
|
+
}): Promise<KimiAuthenticationStatus>;
|
|
81
|
+
/**
|
|
82
|
+
* Rejects only a conclusive login failure. `unknown` is allowed because setup
|
|
83
|
+
* must not spend quota merely to prove authentication.
|
|
84
|
+
*/
|
|
85
|
+
export declare function assertKimiAuthenticated(options?: {
|
|
86
|
+
skipPrereqs?: boolean;
|
|
87
|
+
kimiCodeHome?: string;
|
|
88
|
+
env?: NodeJS.ProcessEnv;
|
|
89
|
+
}): Promise<KimiAuthenticationStatus>;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import type { Provider } from './provider-detect.js';
|
|
2
|
+
/**
|
|
3
|
+
* The three baseline agents — the COMPLETE set of agents the installer
|
|
4
|
+
* ships. The implement pipeline depends on all three. Any additional agent
|
|
5
|
+
* comes from a user-authored profile (`custom-*`), never the installer.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the `allOf` baseline in schemas/profile.v1.json — update
|
|
8
|
+
* both files together if this set ever changes.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CORE_AGENTS: Set<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Rewrite every literal `Skill("opsx:<id>"[, …])` call in a Claude-authored agent
|
|
13
|
+
* body into the Gemini `activate_skill(name="…")` form. Positional skill input
|
|
14
|
+
* (e.g. `"<specName>"`) is dropped because `activate_skill` takes only `name` and
|
|
15
|
+
* the surrounding persona prose already carries the context. Unknown ids are left
|
|
16
|
+
* untouched (better a visible stale ref than a silent `name="undefined"`). This
|
|
17
|
+
* runs ONLY on the gemini render path; Claude/Codex keep the `Skill(...)` form.
|
|
18
|
+
*/
|
|
19
|
+
export declare function translateOpsxSkillCallsForGemini(body: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Port shared Claude-authored prose to Kimi's directory-skill contract.
|
|
22
|
+
*
|
|
23
|
+
* Kimi's TUI/ACP clients intercept `/skill:*`, but a materialized workflow is
|
|
24
|
+
* already running inside a Session and must activate nested workflows through
|
|
25
|
+
* Kimi's built-in `Skill` tool (`{ skill, args }`). Emitting slash text here
|
|
26
|
+
* would silently become ordinary model text under `kimi -p`. Interactive slash
|
|
27
|
+
* examples therefore belong only in AGENTS/docs, never generated skill bodies.
|
|
28
|
+
* This is render-only; canonical Claude/Codex/Gemini templates stay unchanged.
|
|
29
|
+
*/
|
|
30
|
+
export declare function translateClaudeTextForKimi(body: string): string;
|
|
31
|
+
export declare function geminiAgentLimitMetadata(env?: NodeJS.ProcessEnv): string[];
|
|
32
|
+
/**
|
|
33
|
+
* Phase 2 + Phase 3 of the retired install.sh:
|
|
34
|
+
* - Detect prior installation state (.claude/.codex/openspec already present).
|
|
35
|
+
* - Create the directory skeleton.
|
|
36
|
+
* - Copy templates into `.specrails/setup-templates/` (the internal
|
|
37
|
+
* staging dir that placement copies from and `update` diffs against).
|
|
38
|
+
* - Ensure `.gitignore` excludes the runtime artefacts.
|
|
39
|
+
*
|
|
40
|
+
* Placement (`placeArtefacts`) then copies the staged templates directly into
|
|
41
|
+
* the user's live `.claude/agents/` and `.claude/commands/specrails/` dirs so
|
|
42
|
+
* the installer finishes in one pass — no follow-up wizard required.
|
|
43
|
+
*/
|
|
44
|
+
export interface ScaffoldInput {
|
|
45
|
+
/** Absolute path to the specrails-core package (installed via npx). */
|
|
46
|
+
scriptDir: string;
|
|
47
|
+
/**
|
|
48
|
+
* Absolute path to the relocated artifact root — where every Specrails-managed
|
|
49
|
+
* artifact (.specrails/.claude/.codex/.gemini/.kimi-code and instruction/settings files)
|
|
50
|
+
* is written. Under relocate-always this is the `$HOME` workspace, NOT the repo.
|
|
51
|
+
*/
|
|
52
|
+
artifactRoot: string;
|
|
53
|
+
/**
|
|
54
|
+
* Absolute path to the user's repo root — the ONLY thing that stays in-repo is
|
|
55
|
+
* `openspec/**` (installed by init.ts) and git/worktree ops. Used solely by
|
|
56
|
+
* `detectExistingSetup`'s openspec probe and the gitignore no-op guard.
|
|
57
|
+
*/
|
|
58
|
+
codeRoot: string;
|
|
59
|
+
/** Resolved provider from prereqs. */
|
|
60
|
+
provider: Provider;
|
|
61
|
+
/** Derived directory name (`.claude` or `.codex`). */
|
|
62
|
+
providerDir: string;
|
|
63
|
+
/** Optional explicit allow-list used by config-driven installs. */
|
|
64
|
+
selectedAgents?: string[];
|
|
65
|
+
/**
|
|
66
|
+
* When false, the static-placement helpers do NOT create the per-workspace
|
|
67
|
+
* mutable seeds (agent-memory dirs, gemini headless acknowledgments). Used by
|
|
68
|
+
* `installFramework` so the SHARED framework copy stays purely provider-static
|
|
69
|
+
* — the project layer is seeded separately by `assembleProjectWorkspace`.
|
|
70
|
+
* Defaults to true (legacy in-place behaviour for `scaffoldInstallation`).
|
|
71
|
+
*/
|
|
72
|
+
seedProjectDirs?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* When true, place EVERY agent template (the full superset) regardless of
|
|
75
|
+
* `selectedAgents`. Used by `installFramework` so
|
|
76
|
+
* the SHARED framework store is a superset that ANY project's selection can
|
|
77
|
+
* link from — per-project agent filtering then happens at the workspace LINK
|
|
78
|
+
* step (`linkAgentFiles`), not at materialization. Defaults to false (legacy
|
|
79
|
+
* selection-honouring placement for in-place `scaffoldInstallation`).
|
|
80
|
+
*/
|
|
81
|
+
materializeAllAgents?: boolean;
|
|
82
|
+
}
|
|
83
|
+
export interface ScaffoldResult {
|
|
84
|
+
existingSetup: boolean;
|
|
85
|
+
createdDirs: string[];
|
|
86
|
+
copiedFiles: number;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Returns true iff any of the provider directories already contains
|
|
90
|
+
* content. The desktop-app-driven path skips the "merge existing?" prompt and
|
|
91
|
+
* assumes `--yes`; the CLI dispatcher (bin/specrails-core.cjs) should
|
|
92
|
+
* have prompted before entering this phase.
|
|
93
|
+
*/
|
|
94
|
+
export declare function detectExistingSetup(input: Pick<ScaffoldInput, 'artifactRoot' | 'codeRoot' | 'providerDir'>): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Entry point. Creates directories, copies templates, updates
|
|
97
|
+
* .gitignore. Returns a summary for logging / tests.
|
|
98
|
+
*/
|
|
99
|
+
export declare function scaffoldInstallation(input: ScaffoldInput): ScaffoldResult;
|
|
100
|
+
export interface InstallFrameworkInput {
|
|
101
|
+
/** Absolute path to the specrails-core package (templates/ + commands/). */
|
|
102
|
+
scriptDir: string;
|
|
103
|
+
/** Root of the versioned framework store, e.g. `<home>/.specrails/framework`. */
|
|
104
|
+
frameworkDir: string;
|
|
105
|
+
/** Provider whose static subtree is being materialized. */
|
|
106
|
+
provider: Provider;
|
|
107
|
+
/** Derived provider dir (`.claude`/`.codex`/`.gemini`/`.kimi-code`). */
|
|
108
|
+
providerDir: string;
|
|
109
|
+
/** Framework version (the `<version>/` segment). */
|
|
110
|
+
version: string;
|
|
111
|
+
/** Optional explicit agent allow-list (kept for parity with scaffold). */
|
|
112
|
+
selectedAgents?: string[];
|
|
113
|
+
}
|
|
114
|
+
export interface InstallFrameworkResult {
|
|
115
|
+
/** `<frameworkDir>/<version>/<providerDir>` — root of the static subtree. */
|
|
116
|
+
providerFrameworkDir: string;
|
|
117
|
+
/** `<frameworkDir>/<version>` — the version root (also holds setup-templates/). */
|
|
118
|
+
versionDir: string;
|
|
119
|
+
/** True when a fresh materialization happened; false when the idempotent skip fired. */
|
|
120
|
+
materialized: boolean;
|
|
121
|
+
}
|
|
122
|
+
/** Path to the per-version, per-provider materialization marker (manifest hash). */
|
|
123
|
+
export declare function frameworkStampPath(versionDir: string, providerDir: string): string;
|
|
124
|
+
/**
|
|
125
|
+
* Validate one provider in a materialized version without needing the source
|
|
126
|
+
* package. Used by the final swap gate: the stamp identity and current output
|
|
127
|
+
* hash must still agree immediately before `current` moves.
|
|
128
|
+
*/
|
|
129
|
+
export declare function frameworkMaterializationProblem(versionDir: string, version: string, provider: Provider, providerDir: string): string | null;
|
|
130
|
+
/**
|
|
131
|
+
* Materialize the provider-INVARIANT framework subtree ONCE into
|
|
132
|
+
* `<frameworkDir>/<version>/<providerDir>/` (+ `<version>/setup-templates/`).
|
|
133
|
+
* Idempotent: when the providerDir already exists with a matching stamp it is a
|
|
134
|
+
* no-op (the second workspace assemble re-uses the same copy). Writes NO
|
|
135
|
+
* per-workspace state (no agent-memory, no acks, no project-named instruction
|
|
136
|
+
* files) — those are seeded by `assembleProjectWorkspace`.
|
|
137
|
+
*/
|
|
138
|
+
export declare function installFramework(input: InstallFrameworkInput): InstallFrameworkResult;
|
|
139
|
+
/**
|
|
140
|
+
* Atomically point `<frameworkDir>/current` at `<version>` so every workspace's
|
|
141
|
+
* provider links resolve through `current/...` and an update is a single swap.
|
|
142
|
+
*/
|
|
143
|
+
export declare function ensureCurrentSymlink(frameworkDir: string, version: string): void;
|
|
144
|
+
export interface AssembleProjectWorkspaceInput {
|
|
145
|
+
/** The per-project workspace artifact root (= resolveArtifacts artifactRoot). */
|
|
146
|
+
workspace: string;
|
|
147
|
+
/** Root of the versioned framework store (the parent of `current/`). */
|
|
148
|
+
frameworkDir: string;
|
|
149
|
+
/** Provider whose subtrees are linked into the workspace. */
|
|
150
|
+
provider: Provider;
|
|
151
|
+
/** Derived provider dir (`.claude`/`.codex`/`.gemini`/`.kimi-code`). */
|
|
152
|
+
providerDir: string;
|
|
153
|
+
/** Framework version (used for the manifest record). */
|
|
154
|
+
version: string;
|
|
155
|
+
/** The user's real repo (drives PROJECT_NAME + gemini ack keying). */
|
|
156
|
+
codeRoot: string;
|
|
157
|
+
/** specrails-core package dir (for the manifest hash sources). */
|
|
158
|
+
scriptDir: string;
|
|
159
|
+
/**
|
|
160
|
+
* Optional agent allow-list. Drives BOTH which framework agents are LINKED
|
|
161
|
+
* into the workspace (`linkAgentFiles`) AND which agent-memory dirs are seeded.
|
|
162
|
+
* Undefined = the CORE trio only (the lean default). The SHARED framework store
|
|
163
|
+
* is always the full superset; this is where per-project filtering happens.
|
|
164
|
+
*/
|
|
165
|
+
selectedAgents?: string[];
|
|
166
|
+
/**
|
|
167
|
+
* When true, the static provider subtrees (`agents`/`commands`/`skills`/`rules`)
|
|
168
|
+
* and the settings file are COPIED as real files from the framework store into
|
|
169
|
+
* the workspace instead of SYMLINKED. Used by the in-repo standalone install
|
|
170
|
+
* (`init`/`update` with `artifactRoot === codeRoot`) so the repo gets real,
|
|
171
|
+
* committable files — a symlink into `$HOME/.specrails/framework` would be
|
|
172
|
+
* invisible to a standalone user's `claude`/`codex`/`gemini`/`kimi` running in the
|
|
173
|
+
* repo. The PROJECT layer (agent-memory, manifest, instruction files) is real
|
|
174
|
+
* either way. Defaults to false (relocated workspaces symlink — the desktop /
|
|
175
|
+
* `--relocate` path).
|
|
176
|
+
*/
|
|
177
|
+
copyStatics?: boolean;
|
|
178
|
+
}
|
|
179
|
+
export interface AssembleProjectWorkspaceResult {
|
|
180
|
+
/** Per-linked-subtree mechanism, for diagnostics (copy-fallback loses O(1) swap). */
|
|
181
|
+
links: Record<string, 'symlink' | 'junction' | 'copy'>;
|
|
182
|
+
/** Agent ids whose memory dirs were seeded as real writable dirs. */
|
|
183
|
+
seededMemoryAgents: string[];
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Assemble a project workspace with NO network and NO re-materialization: (a)
|
|
187
|
+
* SYMLINK the static providerDir subtrees from `<frameworkDir>/current/
|
|
188
|
+
* <providerDir>/` into `<workspace>/<providerDir>/`, then (b) seed the PROJECT
|
|
189
|
+
* layer as real writable files (agent-memory dirs, the manifest, project-named
|
|
190
|
+
* instruction/settings files, gemini headless acks re-hashed against the LINKED
|
|
191
|
+
* files). `agent-memory/` is NEVER linked.
|
|
192
|
+
*/
|
|
193
|
+
export declare function assembleProjectWorkspace(input: AssembleProjectWorkspaceInput): AssembleProjectWorkspaceResult;
|
|
194
|
+
/**
|
|
195
|
+
* Pre-acknowledge the generated gemini subagents so they load in HEADLESS
|
|
196
|
+
* (`gemini -p`) runs. gemini 0.46+ DISCOVERS `.gemini/agents/*.md` but only
|
|
197
|
+
* ENABLES a project's custom agents after the interactive "New Agents Discovered
|
|
198
|
+
* → Acknowledge and Enable" prompt — which never fires headless, so
|
|
199
|
+
* `invoke_agent sr-architect` returns "Subagent not found" and the implement
|
|
200
|
+
* orchestrator silently falls back to a generic agent (the specialised personas
|
|
201
|
+
* never run, the pipeline degrades). The acknowledgment is a user-global file
|
|
202
|
+
* `~/.gemini/acknowledgments/agents.json` shaped
|
|
203
|
+
* `{ [projectRoot]: { [agentName]: <sha256-hex of the agent .md file> } }`
|
|
204
|
+
* (hash algorithm verified empirically against gemini 0.47 = sha256 of the full
|
|
205
|
+
* file). Writing it at install time makes the freshly-generated agents trusted
|
|
206
|
+
* with no prompt, for both `gemini` CLI and the desktop's headless spawns. The
|
|
207
|
+
* file is MERGED — other projects' and other agents' entries are preserved.
|
|
208
|
+
* Best-effort: any failure is swallowed by the caller (agents still work once
|
|
209
|
+
* acknowledged interactively).
|
|
210
|
+
*/
|
|
211
|
+
export declare function writeGeminiAgentAcknowledgments(repoRoot: string, agentIds: string[], agentsBaseDir?: string): void;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export type KimiThinkingEffort = 'low' | 'high' | 'max';
|
|
2
|
+
export interface KimiInvocationInput {
|
|
3
|
+
/** Raw profile model id. Official short aliases are normalized at launch. */
|
|
4
|
+
model: string;
|
|
5
|
+
/** Plain prompt. Required when `skill` is omitted. */
|
|
6
|
+
prompt?: string;
|
|
7
|
+
/** Safe direct-child skill directory id. Uses the managed runner when set. */
|
|
8
|
+
skill?: string;
|
|
9
|
+
/** Raw skill argument string expanded with Kimi's native placeholder rules. */
|
|
10
|
+
skillArguments?: string;
|
|
11
|
+
/** A session id emitted by a prior `session.resume_hint` event. */
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
thinkingEffort?: KimiThinkingEffort;
|
|
14
|
+
/** Additional source/worktree roots exposed to this independent process. */
|
|
15
|
+
additionalDirs?: string[];
|
|
16
|
+
/** Absolute paths only. Kimi prompt mode has no attachment argv flag. */
|
|
17
|
+
attachmentPaths?: string[];
|
|
18
|
+
/** Override for callers whose workspace exposes the managed runner elsewhere. */
|
|
19
|
+
skillRunnerPath?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface KimiInvocation {
|
|
22
|
+
bin: 'kimi' | 'node';
|
|
23
|
+
args: string[];
|
|
24
|
+
/** Process-environment overlay; no credentials are added or persisted. */
|
|
25
|
+
env: Record<string, string | undefined>;
|
|
26
|
+
prompt: string;
|
|
27
|
+
/** Text piped to the managed runner; never placed in subprocess argv. */
|
|
28
|
+
stdinText?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare const KIMI_SKILL_RUNNER_PATH = ".kimi-code/specrails/run-skill.mjs";
|
|
31
|
+
/**
|
|
32
|
+
* Profiles retain raw provider ids. At the CLI boundary only the three managed
|
|
33
|
+
* Kimi aliases gain their documented `kimi-code/` namespace; custom model ids
|
|
34
|
+
* and already-qualified aliases remain byte-identical.
|
|
35
|
+
*/
|
|
36
|
+
export declare function normalizeKimiCliModel(model: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* Canonical daemon-free Kimi invocation consumed by Desktop and scripts.
|
|
39
|
+
* Plain prompts cross stdin into Core's managed Node helper so they never
|
|
40
|
+
* appear in the host-to-helper argv. The helper must pass the exact user turn
|
|
41
|
+
* through Kimi 0.27's only non-interactive API, `-p <prompt>`: native Kimi
|
|
42
|
+
* binaries therefore expose it in their own process argv, while supported npm
|
|
43
|
+
* Windows shims receive it through the exact stdin bootstrap. Skills also
|
|
44
|
+
* pre-render direct-child SKILL.md because prompt mode treats `/skill:...` as
|
|
45
|
+
* literal user text.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildKimiInvocation(input: KimiInvocationInput): KimiInvocation;
|
|
48
|
+
export type KimiStreamEvent = {
|
|
49
|
+
kind: 'empty';
|
|
50
|
+
} | {
|
|
51
|
+
kind: 'invalid';
|
|
52
|
+
raw: string;
|
|
53
|
+
} | {
|
|
54
|
+
kind: 'assistant';
|
|
55
|
+
content: string;
|
|
56
|
+
raw: Record<string, unknown>;
|
|
57
|
+
} | {
|
|
58
|
+
kind: 'tool';
|
|
59
|
+
raw: Record<string, unknown>;
|
|
60
|
+
} | {
|
|
61
|
+
kind: 'resume_hint';
|
|
62
|
+
sessionId: string;
|
|
63
|
+
raw: Record<string, unknown>;
|
|
64
|
+
} | {
|
|
65
|
+
kind: 'meta';
|
|
66
|
+
raw: Record<string, unknown>;
|
|
67
|
+
} | {
|
|
68
|
+
kind: 'unknown';
|
|
69
|
+
raw: Record<string, unknown>;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Tolerant JSONL parser for Kimi 0.27. Unknown and malformed lines are surfaced
|
|
73
|
+
* to the caller rather than terminating the run. Kimi emits no structured USD
|
|
74
|
+
* cost, so this parser intentionally exposes no fabricated cost field.
|
|
75
|
+
*/
|
|
76
|
+
export declare function parseKimiStreamLine(line: string): KimiStreamEvent;
|
|
77
|
+
/**
|
|
78
|
+
* Returns a resumable id only when Kimi exited successfully and its final
|
|
79
|
+
* non-empty JSONL record is a canonical `session.resume_hint`. Kimi may emit a
|
|
80
|
+
* hint before assigning a non-zero process exit status (for example an
|
|
81
|
+
* incomplete headless goal), so callers must supply the observed child exit
|
|
82
|
+
* code rather than treating the record alone as proof of success.
|
|
83
|
+
*/
|
|
84
|
+
export declare function extractKimiSessionHint(lines: Iterable<string>, exitCode: number | null): string | null;
|