@aihq/harness 0.2.0-rc.0 → 0.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/NOTICE +41 -0
- package/README.md +33 -8
- package/dist/{chunk-S7XFTZJW.js → chunk-7GVBGS5N.js} +1423 -637
- package/dist/chunk-7GVBGS5N.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +64 -5
- package/dist/index.js +3 -1
- package/package.json +5 -2
- package/dist/chunk-S7XFTZJW.js.map +0 -1
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -186,7 +186,7 @@ type Verdict = "pass" | "fail" | "skip";
|
|
|
186
186
|
* sealed: a new failure mode means a new member here PLUS the `code` set at the
|
|
187
187
|
* emitter; never derive a code by matching `detail`.
|
|
188
188
|
*/
|
|
189
|
-
type CheckCode = "env.node-runtime" | "env.git-missing" | "env.dev-tool-missing" | "env.tool-install-blocked" | "cert.ca-missing" | "tls.verify-failed" | "npm.runtime-broken" | "path.missing" | "mcp.blocked" | "mcp.uv-missing" | "mcp.config-missing" | "mcp.unvendored-offline" | "mcp.policy-denied" | "mcp.hardcoded-secret" | "mcp.allowlist-drift" | "cli.not-detected" | "cli.config-only" | "cli.bootloader-missing" | "cli.bootloader-drift" | "cli.wont-load" | "canon.router-missing" | "canon.context-dir-missing" | "canon.lint-failed" | "canon.adoptable" | "canon.cli-native-unmigrated" | "secrets.plaintext-detected" | "guardrails.gitleaks-missing" | "usage.no-data" | "scale.code-review-graph-missing" | "contract.path-unportable" | "contract.stale" | "org-policy.drift" | "report.context-over-budget" | "report.low-adoption" | "report.contract-untrue" | "trust.fetch-blocked" | "trust.detector-unavailable" | "trust.hidden-unicode" | "trust.prompt-injection" | "trust.source-changed" | "trust.auto-exec-hook" | "trust.dependency-confusion" | "trust.typosquat" | "trust.malicious-code" | "trust.source-drift" | "trust.unpinned-dependency" | "trust.untrusted-publisher" | "trust.unsigned-source";
|
|
189
|
+
type CheckCode = "env.node-runtime" | "env.git-missing" | "env.dev-tool-missing" | "env.tool-install-blocked" | "cert.ca-missing" | "tls.verify-failed" | "npm.runtime-broken" | "path.missing" | "mcp.blocked" | "mcp.uv-missing" | "mcp.config-missing" | "mcp.unvendored-offline" | "mcp.policy-denied" | "mcp.hardcoded-secret" | "mcp.allowlist-drift" | "cli.not-detected" | "cli.config-only" | "cli.bootloader-missing" | "cli.bootloader-drift" | "cli.wont-load" | "canon.router-missing" | "canon.context-dir-missing" | "canon.lint-failed" | "canon.adoptable" | "canon.cli-native-unmigrated" | "secrets.plaintext-detected" | "guardrails.gitleaks-missing" | "usage.no-data" | "scale.code-review-graph-missing" | "contract.path-unportable" | "contract.stale" | "org-policy.drift" | "report.context-over-budget" | "report.low-adoption" | "report.contract-untrue" | "ready.blocked" | "trust.fetch-blocked" | "trust.detector-unavailable" | "trust.hidden-unicode" | "trust.prompt-injection" | "trust.source-changed" | "trust.auto-exec-hook" | "trust.dependency-confusion" | "trust.typosquat" | "trust.malicious-code" | "trust.source-drift" | "trust.unpinned-dependency" | "trust.untrusted-publisher" | "trust.unsigned-source";
|
|
190
190
|
interface Check {
|
|
191
191
|
name: string;
|
|
192
192
|
verdict: Verdict;
|
|
@@ -246,10 +246,14 @@ declare class VerificationReport {
|
|
|
246
246
|
* - `digest`: a read-only computed result printed verbatim (an analytics
|
|
247
247
|
* report / roll-up) plus optional structured `data` echoed into
|
|
248
248
|
* `--json` — mutates nothing, never contacts a remote system.
|
|
249
|
+
* - `remove`: delete a repo-LOCAL file aih exclusively owns (a stale per-CLI
|
|
250
|
+
* adapter / kiro extra when its CLI is dropped), reversibly by
|
|
251
|
+
* default (moved to gitignored `.aih/legacy/`). Fail-closed:
|
|
252
|
+
* contained, symlink-guarded, backed up before unlink. Never remote.
|
|
249
253
|
* Because no action kind can mutate a remote system, an autonomous run cannot
|
|
250
254
|
* "fake provisioning" — the capability simply does not exist.
|
|
251
255
|
*/
|
|
252
|
-
type ActionKind = "write" | "probe" | "doc" | "exec" | "envblock" | "digest";
|
|
256
|
+
type ActionKind = "write" | "probe" | "doc" | "exec" | "envblock" | "digest" | "remove";
|
|
253
257
|
interface WriteAction {
|
|
254
258
|
kind: "write";
|
|
255
259
|
path: string;
|
|
@@ -346,7 +350,23 @@ interface DigestAction {
|
|
|
346
350
|
data?: unknown;
|
|
347
351
|
};
|
|
348
352
|
}
|
|
349
|
-
|
|
353
|
+
/**
|
|
354
|
+
* Remove a repo-LOCAL file that aih exclusively owns — aih's only destructive
|
|
355
|
+
* action. Emitted solely by `aih prune` for artifacts its detection proved
|
|
356
|
+
* aih-owned (a per-CLI adapter note, a kiro steering/hook extra) once the CLI is
|
|
357
|
+
* dropped. The executor fails closed: mandatory {@link assertContained} on the raw
|
|
358
|
+
* path (no `external` field exists, so a global `~/home` file is structurally
|
|
359
|
+
* unreachable), a symlink guard, and a backup before unlink. It MOVES the file to
|
|
360
|
+
* gitignored `.aih/legacy/<path>` (reversible) — the move itself is the backup, so a
|
|
361
|
+
* dropped CLI's artifacts can always be restored by moving them back.
|
|
362
|
+
*/
|
|
363
|
+
interface RemoveAction {
|
|
364
|
+
kind: "remove";
|
|
365
|
+
/** Repo-relative path of the file to remove. */
|
|
366
|
+
path: string;
|
|
367
|
+
describe: string;
|
|
368
|
+
}
|
|
369
|
+
type Action = WriteAction | DocAction | ProbeAction | ExecAction | EnvBlockAction | DigestAction | RemoveAction;
|
|
350
370
|
interface Plan {
|
|
351
371
|
capability: string;
|
|
352
372
|
actions: Action[];
|
|
@@ -366,6 +386,13 @@ interface PlanContext {
|
|
|
366
386
|
/** When true, probe actions run and contribute to the verification report. */
|
|
367
387
|
verify: boolean;
|
|
368
388
|
json: boolean;
|
|
389
|
+
/**
|
|
390
|
+
* Local process runner. During `plan()` (dry-run) only READ-ONLY tools on FIXED targets
|
|
391
|
+
* may be run, and only to DECIDE the plan (heal's node/npm/TLS checks pick the repair
|
|
392
|
+
* ladder; certs reads the OS trust store; report shells `git` for stats). Never shell out
|
|
393
|
+
* an arbitrary or interpolated command at plan time — that is the `AIH_GRAPH_CMD` class of
|
|
394
|
+
* bug. The read-only allowlist is pinned by `tests/internals/plan-purity.test.ts` (#35).
|
|
395
|
+
*/
|
|
369
396
|
run: Runner;
|
|
370
397
|
host: HostAdapter;
|
|
371
398
|
env: NodeJS.ProcessEnv;
|
|
@@ -413,6 +440,13 @@ interface CommandSpec {
|
|
|
413
440
|
* blocking the report on a dirty tree is wrong.
|
|
414
441
|
*/
|
|
415
442
|
skipWorktreeGate?: boolean;
|
|
443
|
+
/**
|
|
444
|
+
* Wire an interactive prompter for this command in a TTY even without `--detect`,
|
|
445
|
+
* so a bare run can offer a confirmation (e.g. `aih ready` asking to install the
|
|
446
|
+
* missing core tools). Still suppressed under `--json`/`--yes`/non-TTY, so
|
|
447
|
+
* automation stays non-interactive.
|
|
448
|
+
*/
|
|
449
|
+
wantsInstallPrompt?: boolean;
|
|
416
450
|
}
|
|
417
451
|
declare function writeText(path: string, contents: string, describe: string, opts?: {
|
|
418
452
|
mode?: number;
|
|
@@ -437,6 +471,7 @@ declare function exec(describe: string, argv: string[], opts?: {
|
|
|
437
471
|
blockProbesOnFailure?: boolean;
|
|
438
472
|
}): ExecAction;
|
|
439
473
|
declare function envBlock(path: string, scope: string, shell: EnvShell, vars: EnvVar[], describe: string): EnvBlockAction;
|
|
474
|
+
declare function remove(path: string, describe: string): RemoveAction;
|
|
440
475
|
declare function plan(capability: string, ...actions: Action[]): Plan;
|
|
441
476
|
|
|
442
477
|
/** Capability commands (repo/workstation mutators), dry-run by default. */
|
|
@@ -520,6 +555,14 @@ interface WriteSummary {
|
|
|
520
555
|
*/
|
|
521
556
|
effect: "create" | "overwrite" | "merge" | "unchanged" | "kept";
|
|
522
557
|
}
|
|
558
|
+
interface RemoveSummary {
|
|
559
|
+
path: string;
|
|
560
|
+
describe: string;
|
|
561
|
+
/** `remove` = present, will move to `.aih/legacy/`; `absent` = nothing on disk. */
|
|
562
|
+
effect: "remove" | "absent";
|
|
563
|
+
/** Repo-relative `.aih/legacy/` destination, when effect is `remove`. */
|
|
564
|
+
to?: string;
|
|
565
|
+
}
|
|
523
566
|
interface PlanResult {
|
|
524
567
|
capability: string;
|
|
525
568
|
applied: boolean;
|
|
@@ -545,6 +588,8 @@ interface PlanResult {
|
|
|
545
588
|
data?: unknown;
|
|
546
589
|
}[];
|
|
547
590
|
backups: string[];
|
|
591
|
+
/** Files aih removed (moved to `.aih/legacy/`) or would remove (dry-run). */
|
|
592
|
+
removed: RemoveSummary[];
|
|
548
593
|
report?: VerificationReport;
|
|
549
594
|
}
|
|
550
595
|
/**
|
|
@@ -601,9 +646,15 @@ interface StagedWrite {
|
|
|
601
646
|
contents: string;
|
|
602
647
|
mode?: number;
|
|
603
648
|
}
|
|
649
|
+
interface AppliedRemoval {
|
|
650
|
+
path: string;
|
|
651
|
+
legacyPath: string;
|
|
652
|
+
}
|
|
604
653
|
interface FsTxnResult {
|
|
605
654
|
written: string[];
|
|
606
655
|
backups: string[];
|
|
656
|
+
/** Files moved out of the tree (source → `.aih/legacy/` destination). */
|
|
657
|
+
removed: AppliedRemoval[];
|
|
607
658
|
}
|
|
608
659
|
/**
|
|
609
660
|
* Stages writes in memory and commits them atomically. Each existing target is
|
|
@@ -614,7 +665,15 @@ interface FsTxnResult {
|
|
|
614
665
|
*/
|
|
615
666
|
declare class FsTransaction {
|
|
616
667
|
private staged;
|
|
668
|
+
private stagedRemovals;
|
|
617
669
|
stage(path: string, contents: string, mode?: number): void;
|
|
670
|
+
/**
|
|
671
|
+
* Stage a file REMOVAL as a reversible move to `legacyPath` (under gitignored
|
|
672
|
+
* `.aih/legacy/`). The move IS the backup: rollback (and the user) restore by
|
|
673
|
+
* moving it back. Symlinks are refused at commit (moving a link then restoring it
|
|
674
|
+
* would recreate a regular file). No-op if the source is already gone.
|
|
675
|
+
*/
|
|
676
|
+
stageRemoval(path: string, legacyPath: string): void;
|
|
618
677
|
preview(): ReadonlyArray<StagedWrite>;
|
|
619
678
|
commit(): FsTxnResult;
|
|
620
679
|
}
|
|
@@ -699,8 +758,8 @@ declare function parseCertLines(stdout: string): CertEntry[];
|
|
|
699
758
|
*/
|
|
700
759
|
declare function parsePemBlocks(stdout: string, subject?: string): CertEntry[];
|
|
701
760
|
|
|
702
|
-
declare const VERSION = "0.
|
|
761
|
+
declare const VERSION = "0.3.0";
|
|
703
762
|
/** Build the configured commander program. Imported by both the CLI entry and tests. */
|
|
704
763
|
declare function buildProgram(): Command;
|
|
705
764
|
|
|
706
|
-
export { ALL_COMMANDS, type AccelBackend, type Action, type ActionKind, type AdapterFactory, AihError, CAPABILITIES, type CertEntry, type Check, type CheckCode, type CommandOption, type CommandSpec, ContextDir, type DigestAction, DirtyWorktreeError, type DocAction, type EnvBlockAction, type EnvShell, type EnvVar, type ExecAction, FsTransaction, FsTxnError, type FsTxnResult, type GpuInfo, type GpuVendor, type HostAdapter, type HostAdapterOptions, MergeError, NotImplementedError, PathContainmentError, type Plan, type PlanContext, type PlanFn, type PlanResult, type Platform, PlatformError, type ProbeAction, READONLY, type RunOptions, type RunResult, type Runner, type Settings, SettingsError, VERSION, type VdiInfo, type Verdict, VerificationError, VerificationReport, type WriteAction, type WriteSummary, beginMarker, buildProgram, deepMerge, defaultRunner, derBase64ToPem, digest, doc, dynamicDigest, endMarker, ensureTrailingNewline, envBlock, exec, executePlan, fakeRunner, formatExport, frontmatter, indent, isPlainObject, jsonFile, lines, loadSettings, makeHostAdapter, managedBlock, missingToolRunner, parseCertLines, parseFirstInt, parseJsoncText, parseNvidiaSmi, parsePemBlocks, plan, probe, probeMany, readIfExists, registerCommands, removeManagedBlock, resolveContents, resolvePlatform, retryTransient, safeCaPattern, stripTrailingNewlines, summarizeResult, upsertManagedBlock, upsertTextBlock, vdiFromEnv, writeArtifact, writeJson, writeText };
|
|
765
|
+
export { ALL_COMMANDS, type AccelBackend, type Action, type ActionKind, type AdapterFactory, AihError, CAPABILITIES, type CertEntry, type Check, type CheckCode, type CommandOption, type CommandSpec, ContextDir, type DigestAction, DirtyWorktreeError, type DocAction, type EnvBlockAction, type EnvShell, type EnvVar, type ExecAction, FsTransaction, FsTxnError, type FsTxnResult, type GpuInfo, type GpuVendor, type HostAdapter, type HostAdapterOptions, MergeError, NotImplementedError, PathContainmentError, type Plan, type PlanContext, type PlanFn, type PlanResult, type Platform, PlatformError, type ProbeAction, READONLY, type RemoveAction, type RemoveSummary, type RunOptions, type RunResult, type Runner, type Settings, SettingsError, VERSION, type VdiInfo, type Verdict, VerificationError, VerificationReport, type WriteAction, type WriteSummary, beginMarker, buildProgram, deepMerge, defaultRunner, derBase64ToPem, digest, doc, dynamicDigest, endMarker, ensureTrailingNewline, envBlock, exec, executePlan, fakeRunner, formatExport, frontmatter, indent, isPlainObject, jsonFile, lines, loadSettings, makeHostAdapter, managedBlock, missingToolRunner, parseCertLines, parseFirstInt, parseJsoncText, parseNvidiaSmi, parsePemBlocks, plan, probe, probeMany, readIfExists, registerCommands, remove, removeManagedBlock, resolveContents, resolvePlatform, retryTransient, safeCaPattern, stripTrailingNewlines, summarizeResult, upsertManagedBlock, upsertTextBlock, vdiFromEnv, writeArtifact, writeJson, writeText };
|
package/dist/index.js
CHANGED
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
probeMany,
|
|
50
50
|
readIfExists,
|
|
51
51
|
registerCommands,
|
|
52
|
+
remove,
|
|
52
53
|
removeManagedBlock,
|
|
53
54
|
resolveContents,
|
|
54
55
|
resolvePlatform,
|
|
@@ -62,7 +63,7 @@ import {
|
|
|
62
63
|
writeArtifact,
|
|
63
64
|
writeJson,
|
|
64
65
|
writeText
|
|
65
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-7GVBGS5N.js";
|
|
66
67
|
export {
|
|
67
68
|
ALL_COMMANDS,
|
|
68
69
|
AihError,
|
|
@@ -114,6 +115,7 @@ export {
|
|
|
114
115
|
probeMany,
|
|
115
116
|
readIfExists,
|
|
116
117
|
registerCommands,
|
|
118
|
+
remove,
|
|
117
119
|
removeManagedBlock,
|
|
118
120
|
resolveContents,
|
|
119
121
|
resolvePlatform,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aihq/harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Enterprise AI Bootstrapping Harness — bootstraps governed, proxy-safe AI coding into workstations and repos",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
-
"README.md"
|
|
19
|
+
"README.md",
|
|
20
|
+
"NOTICE"
|
|
20
21
|
],
|
|
21
22
|
"engines": {
|
|
22
23
|
"node": ">=20"
|
|
@@ -57,6 +58,8 @@
|
|
|
57
58
|
"@biomejs/biome": "^2.5.1",
|
|
58
59
|
"@types/node": "^26.0.1",
|
|
59
60
|
"@vitest/coverage-v8": "^4.1.9",
|
|
61
|
+
"ajv": "^8.20.0",
|
|
62
|
+
"ajv-formats": "^3.0.1",
|
|
60
63
|
"happy-dom": "^20.10.6",
|
|
61
64
|
"tsup": "^8.5.1",
|
|
62
65
|
"tsx": "^4.22.4",
|