@kici-dev/agent 0.1.10 → 0.1.11

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.
@@ -1,17 +1,22 @@
1
1
  /**
2
2
  * Inline dependency installation for graceful degradation.
3
3
  *
4
- * When dep cache is unavailable or download fails, the agent falls back
5
- * to running npm install directly.
4
+ * When the dep cache is unavailable or a download fails, the agent installs
5
+ * `.kici/` dependencies directly with the repository's package manager.
6
6
  *
7
- * Only npm is supported — it ships with every Node.js installation.
8
- * .kici/package.json is required — its presence signals deps should be installed.
7
+ * The package manager is detected from the cloned repo (npm / pnpm); the
8
+ * presence of `.kici/package.json` signals that deps should be installed. npm
9
+ * is the default and ships with every Node.js install; pnpm is used when the
10
+ * repo is a pnpm workspace so a `.kici/` member can resolve in-repo
11
+ * `workspace:` siblings. yarn is detected but not yet supported and is
12
+ * rejected with an actionable error.
9
13
  *
10
- * Security: npm runs with an isolated per-invocation cache directory to prevent
11
- * cache poisoning across build jobs. A malicious package.json in one repo cannot
12
- * taint the cache used by subsequent builds. The same pressure rules out letting
13
- * lifecycle scripts see synthesized auth env vars — npm runs with
14
- * `--ignore-scripts` whenever a private registry is configured.
14
+ * Security: the install runs with an isolated per-invocation cache/store
15
+ * directory to prevent cache poisoning across build jobs — a malicious
16
+ * package.json in one repo cannot taint the cache used by subsequent builds.
17
+ * The same pressure rules out letting lifecycle scripts see synthesized auth
18
+ * env vars — the install runs with `--ignore-scripts` whenever a private
19
+ * registry is configured.
15
20
  */
16
21
  import { type NpmRegistrySpec } from './npm-registry-config.js';
17
22
  export interface InstallDepsOptions {
@@ -21,24 +26,27 @@ export interface InstallDepsOptions {
21
26
  installEnvSecrets?: Record<string, string>;
22
27
  /** Short job-scoped nonce — used as suffix on synthesized env-var names. */
23
28
  jobIdShort?: string;
29
+ /**
30
+ * Clone root (repo root). Package-manager detection runs against it first,
31
+ * then falls back to `kiciDir`. Defaults to `dirname(kiciDir)`.
32
+ */
33
+ repoRoot?: string;
24
34
  }
25
35
  /**
26
- * Install dependencies inline using npm.
36
+ * Install `.kici/` dependencies inline with the repo's package manager.
27
37
  *
28
- * Falls back to this when the dep cache is unavailable or download fails.
38
+ * Falls back to this when the dep cache is unavailable or a download fails.
39
+ * The install runs with an isolated cache/store directory (created in
40
+ * `os.tmpdir()`) to prevent cache poisoning between build jobs; the directory
41
+ * is removed after installation.
29
42
  *
30
- * npm runs with an isolated cache directory (created in os.tmpdir()) to prevent
31
- * cache poisoning between build jobs. The cache is removed after installation.
43
+ * If `opts.npmRegistries` / `opts.installEnvSecrets` is provided, a job-scoped
44
+ * `.kici/.npmrc` overlay is synthesized for the install, restored in `finally`,
45
+ * and the install runs with `--ignore-scripts` so lifecycle scripts in a
46
+ * committed `package.json` cannot exfiltrate the synthesized token env vars.
32
47
  *
33
- * If `opts.npmRegistries` / `opts.installEnvSecrets` is provided, the helper
34
- * synthesizes a job-scoped `.kici/.npmrc` overlay for the install, restores
35
- * the original file in `finally`, and runs npm with `--ignore-scripts` so
36
- * lifecycle scripts in committed `package.json` cannot exfiltrate the
37
- * synthesized token env vars.
38
- *
39
- * @param kiciDir - Path to the .kici/ directory containing package.json
40
- * @param opts - Optional registry / installEnv configuration. When absent,
41
- * behavior is identical to the pre-private-registry version.
48
+ * @param kiciDir - Path to the `.kici/` directory containing package.json.
49
+ * @param opts - Optional registry / installEnv / repoRoot configuration.
42
50
  */
43
51
  export declare function installDeps(kiciDir: string, opts?: InstallDepsOptions): Promise<void>;
44
52
  //# sourceMappingURL=dep-installer.d.ts.map
@@ -1,22 +1,29 @@
1
1
  /**
2
- * Node_modules tarball creation for build agents.
2
+ * Dependency tarball creation for build agents.
3
3
  *
4
- * After installing dependencies in .kici/, packs node_modules
5
- * into a gzip tarball for upload to the dep cache.
4
+ * After installing dependencies the build agent packs the dependency closure
5
+ * into a gzip tarball for upload to the dep cache. The closure is packed
6
+ * **repo-root-relative** (cwd = the clone root) so restore is a single layout
7
+ * regardless of package manager:
6
8
  *
7
- * Uses tar.gz format (Node.js built-in zlib, no external binary needed).
8
- * Uses portable mode to strip user/group info for cross-machine consistency.
9
+ * - npm / yarn: just `.kici/node_modules`.
10
+ * - pnpm: `.kici/node_modules` plus the repo-root `node_modules/.pnpm` virtual
11
+ * store and the in-repo `workspace:` sibling package directories `.kici`
12
+ * depends on (with their built output). pnpm lays `.kici/node_modules` out as
13
+ * symlinks into the root store and into sibling dirs that live outside
14
+ * `.kici/`, so packing `.kici/node_modules` alone would capture dangling
15
+ * links — the store and siblings must travel together.
16
+ *
17
+ * Uses tar.gz (Node.js built-in zlib, no external binary) in portable mode to
18
+ * strip user/group info for cross-machine consistency; symlinks are preserved
19
+ * as symlinks so the pnpm link graph restores intact.
9
20
  */
10
21
  /**
11
- * Pack node_modules into a gzip tarball and compute its SHA-256 hash.
12
- *
13
- * Creates a tar.gz archive of the `node_modules/` directory relative to
14
- * kiciDir. The tarball is created in-memory and returned as a Buffer
15
- * along with its content hash.
22
+ * Pack the dependency closure into a gzip tarball and compute its SHA-256 hash.
16
23
  *
17
- * @param kiciDir - Path to the .kici/ directory containing node_modules/
18
- * @returns Object with tarball Buffer and SHA-256 hash string
19
- * @throws Error if node_modules/ does not exist in kiciDir
24
+ * @param kiciDir - Path to the `.kici/` directory containing node_modules/.
25
+ * @returns Object with the tarball Buffer and its SHA-256 hash string.
26
+ * @throws Error if `.kici/node_modules` does not exist.
20
27
  */
21
28
  export declare function packNodeModules(kiciDir: string): Promise<{
22
29
  tarball: Buffer;
@@ -69,13 +69,17 @@ export declare function excludeScratchFromGit(repoWorkDir: string): Promise<void
69
69
  */
70
70
  export declare function resolveOrchestratorUrl(url: string): string;
71
71
  /**
72
- * Restore dependencies from a cached tarball.
72
+ * Restore dependencies from a cached tarball into the cloned repo.
73
73
  *
74
- * For HTTP/HTTPS URLs: uses a streaming pipeline (response -> hash -> gunzip -> tar)
75
- * with a 5-minute timeout and up to 2 retries. This avoids buffering entire tarballs
76
- * in memory, eliminating memory spikes proportional to tarball size.
74
+ * The tarball is packed repo-root-relative (see `dep-packer.ts`): every manager
75
+ * carries `.kici/node_modules`; pnpm additionally carries the root
76
+ * `node_modules/.pnpm` store and the in-repo workspace siblings `.kici` resolves.
77
+ * Restore extracts into a scratch dir, then moves each entry into place — one
78
+ * code path for all managers.
77
79
  *
78
- * For file:// URLs: uses a buffer-based approach (local, no streaming benefit).
80
+ * For HTTP/HTTPS URLs: a streaming pipeline (response -> hash -> gunzip -> tar)
81
+ * with a 5-minute timeout and up to 2 retries avoids buffering whole tarballs.
82
+ * For file:// URLs: a buffer-based approach (local, no streaming benefit).
79
83
  *
80
84
  * @param workDir - Root directory of the cloned repository
81
85
  * @param depsUrl - URL to the dependency tarball (http://, https://, or file://)
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Pre-install validation for `.kici/` dependency specifiers.
3
+ *
4
+ * The agent clones a single source repository and installs its `.kici/`
5
+ * dependencies with the repo's package manager. Local-protocol specifiers —
6
+ * `workspace:`, `file:`, `link:`, `portal:` — resolve a dependency against
7
+ * another package on the same filesystem rather than a registry. Whether they
8
+ * are resolvable depends on the manager and the layout:
9
+ *
10
+ * - npm has no `workspace:` protocol and cannot resolve any of these from a
11
+ * registry, so they are rejected up front with an actionable message
12
+ * instead of the raw `EUNSUPPORTEDPROTOCOL` npm would emit.
13
+ * - pnpm resolves `workspace:` against the repo's pnpm workspace (the agent
14
+ * clones the whole repo, so an in-repo sibling is present), and resolves
15
+ * `file:`/`link:`/`portal:` against a path — allowed when that path stays
16
+ * inside the cloned repo, rejected when it escapes the clone.
17
+ *
18
+ * This module performs that classification so unresolvable specifiers fail
19
+ * fast with guidance rather than a cryptic install error.
20
+ */
21
+ import { PackageManager } from '@kici-dev/shared/package-manager';
22
+ /** Local-protocol specifier prefixes that resolve against the filesystem. */
23
+ export declare enum LocalDepProtocol {
24
+ Workspace = "workspace:",
25
+ File = "file:",
26
+ Link = "link:",
27
+ Portal = "portal:"
28
+ }
29
+ /** A dependency whose specifier uses a local (filesystem) protocol. */
30
+ export interface LocalProtocolDep {
31
+ name: string;
32
+ spec: string;
33
+ protocol: LocalDepProtocol;
34
+ }
35
+ interface PackageJsonShape {
36
+ [field: string]: unknown;
37
+ }
38
+ /**
39
+ * Scan a parsed `.kici/package.json` for dependency specifiers that use a
40
+ * local protocol (`workspace:`/`file:`/`link:`/`portal:`). Returns one entry
41
+ * per dependency, in field order. Returns an empty array when there are none.
42
+ */
43
+ export declare function findLocalProtocolDeps(pkg: PackageJsonShape): LocalProtocolDep[];
44
+ /**
45
+ * Whether `.kici/package.json` declares any local-protocol dependency. Used to
46
+ * decide whether the agent must build the in-repo workspace dependency closure
47
+ * after a pnpm install (so a `workspace:` sibling's build output exists before
48
+ * the workflow that imports it loads).
49
+ */
50
+ export declare function kiciHasLocalProtocolDeps(kiciDir: string): Promise<boolean>;
51
+ /** Build the actionable error for unresolvable local-protocol dependencies. */
52
+ export declare function formatUnresolvableDepError(offenders: readonly LocalProtocolDep[], packageManager: PackageManager): string;
53
+ /**
54
+ * Throw an actionable error when `.kici/package.json` declares a local-protocol
55
+ * dependency the detected package manager cannot resolve from the single cloned
56
+ * repository. A missing or unparseable package.json is left for the install to
57
+ * report.
58
+ */
59
+ export declare function assertResolvableDeps(args: {
60
+ kiciDir: string;
61
+ repoRoot: string;
62
+ packageManager: PackageManager;
63
+ }): Promise<void>;
64
+ export {};
65
+ //# sourceMappingURL=validate-kici-deps.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  export { loadConfig, type AppConfig } from './config.js';
2
+ export { installDeps, type InstallDepsOptions } from './execution/dep-installer.js';
3
+ export { findLocalProtocolDeps, assertResolvableDeps, formatUnresolvableDepError, kiciHasLocalProtocolDeps, LocalDepProtocol, type LocalProtocolDep, } from './execution/validate-kici-deps.js';
2
4
  //# sourceMappingURL=index.d.ts.map