@iamu-dev/iamu 0.0.0-stage → 0.2.0-beta.10
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/LICENSE +9 -0
- package/README.md +103 -2
- package/dist/adapters/claude-plugin.d.ts +13 -0
- package/dist/adapters/registry.d.ts +6 -0
- package/dist/adapters/types.d.ts +19 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +22853 -0
- package/dist/build-info.d.ts +53 -0
- package/dist/cloud-url.d.ts +19 -0
- package/dist/commands/auth-http.d.ts +37 -0
- package/dist/commands/auth-project-choice.d.ts +74 -0
- package/dist/commands/auth-token-input.d.ts +21 -0
- package/dist/commands/auth.d.ts +84 -0
- package/dist/commands/browse-actions.d.ts +56 -0
- package/dist/commands/browse-driver.d.ts +117 -0
- package/dist/commands/browse.d.ts +170 -0
- package/dist/commands/cloud-push.d.ts +27 -0
- package/dist/commands/complete.d.ts +132 -0
- package/dist/commands/completion.d.ts +2 -0
- package/dist/commands/context.d.ts +58 -0
- package/dist/commands/credentials.d.ts +144 -0
- package/dist/commands/diff-filter.d.ts +11 -0
- package/dist/commands/doctor.d.ts +33 -0
- package/dist/commands/evaluate.d.ts +32 -0
- package/dist/commands/explore-crawl.d.ts +67 -0
- package/dist/commands/explore.d.ts +52 -0
- package/dist/commands/findings.d.ts +7 -0
- package/dist/commands/init.d.ts +16 -0
- package/dist/commands/instructions-walk.d.ts +69 -0
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/match.d.ts +13 -0
- package/dist/commands/mcp-config.d.ts +10 -0
- package/dist/commands/new-entity.d.ts +28 -0
- package/dist/commands/new-finding.d.ts +19 -0
- package/dist/commands/open.d.ts +8 -0
- package/dist/commands/port.d.ts +17 -0
- package/dist/commands/prune.d.ts +11 -0
- package/dist/commands/pull.d.ts +5 -0
- package/dist/commands/register-cloud.d.ts +5 -0
- package/dist/commands/register-findings.d.ts +5 -0
- package/dist/commands/register-project.d.ts +5 -0
- package/dist/commands/register-walkthrough.d.ts +5 -0
- package/dist/commands/register.d.ts +10 -0
- package/dist/commands/report.d.ts +3 -0
- package/dist/commands/serve.d.ts +11 -0
- package/dist/commands/skills.d.ts +34 -0
- package/dist/commands/start-run.d.ts +54 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/step-numbering.d.ts +87 -0
- package/dist/commands/step.d.ts +95 -0
- package/dist/commands/sync.d.ts +6 -0
- package/dist/commands/triage.d.ts +21 -0
- package/dist/commands/update.d.ts +4 -0
- package/dist/commands/validate.d.ts +8 -0
- package/dist/commands/view-results.d.ts +9 -0
- package/dist/eval/gemini-eval-cli.d.ts +10 -0
- package/dist/eval/gemini-eval-cli.js +976 -0
- package/dist/eval/gemini-walker.d.ts +46 -0
- package/dist/eval/walkthrough-evaluator.d.ts +61 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +22700 -0
- package/dist/sync-mcp/fatal.d.ts +42 -0
- package/dist/sync-mcp/server.d.ts +1 -0
- package/dist/sync-mcp/tools.d.ts +12 -0
- package/dist/templates/prompts/combine.md +69 -0
- package/dist/templates/prompts/complete.md +132 -0
- package/dist/templates/prompts/evaluate.md +64 -0
- package/dist/templates/prompts/outline.md +54 -0
- package/dist/templates/prompts/persona.md +40 -0
- package/dist/templates/prompts/walk.md +179 -0
- package/dist/templates/skills/iamu-findings.md +266 -0
- package/dist/templates/skills/iamu-new.md +263 -0
- package/dist/templates/skills/iamu-propose.md +157 -0
- package/dist/templates/skills/iamu-run.md +520 -0
- package/dist/templates/skills/iamu-setup.md +270 -0
- package/dist/templates/skills/iamu-status.md +71 -0
- package/dist/templates.d.ts +10 -0
- package/dist/ui/journey-diff.d.ts +3 -0
- package/dist/ui/json.d.ts +6 -0
- package/dist/ui/logger.d.ts +5 -0
- package/dist/ui/panic.d.ts +11 -0
- package/dist/ui/symbols.d.ts +11 -0
- package/dist/ui/table.d.ts +20 -0
- package/dist/ui/update-check.d.ts +6 -0
- package/dist/worktree-state.d.ts +49 -0
- package/package.json +72 -3
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { type JourneyDiff, type RevisitPlaceCoverage, type VerificationSummary, type WalkthroughManifest } from "@iamu-dev/local-store";
|
|
2
|
+
import { type CanonicalWalkthrough, type RunViewport } from "@iamu-dev/protocol";
|
|
3
|
+
import { type CloudRunInfo } from "./cloud-push.js";
|
|
4
|
+
export interface CompleteOptions {
|
|
5
|
+
cwd?: string;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
force?: boolean;
|
|
8
|
+
yes?: boolean;
|
|
9
|
+
prompt?: boolean;
|
|
10
|
+
view?: boolean;
|
|
11
|
+
strictProvenance?: boolean;
|
|
12
|
+
push?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** Non-fatal observations made while completing, reported after assembly. */
|
|
15
|
+
export interface CompletionExtras {
|
|
16
|
+
revisit: RevisitReport | null;
|
|
17
|
+
viewportWarning: string | null;
|
|
18
|
+
codeWarning: string | null;
|
|
19
|
+
cloudInfo: CloudRunInfo | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* `iamu complete <run-id>`: assemble canonical.json + report.md, mark the
|
|
23
|
+
* run completed, push it when cloud-linked and report the outcome.
|
|
24
|
+
*/
|
|
25
|
+
export declare function complete(runId: string, opts?: CompleteOptions): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* The run's completion time. `--force` reassembles the report of a finished
|
|
28
|
+
* run; the run still finished when it first completed. Re-stamping would
|
|
29
|
+
* move every re-assembled run to "now", which breaks run ordering and
|
|
30
|
+
* durations downstream.
|
|
31
|
+
*/
|
|
32
|
+
export declare function pickCompletedAt(manifest: Pick<WalkthroughManifest, "completed_at">, now?: () => Date): string;
|
|
33
|
+
/** The manifest with its status flipped to completed. */
|
|
34
|
+
export declare function completedManifest(manifest: WalkthroughManifest, completedAt: string): WalkthroughManifest;
|
|
35
|
+
/** Persist the completed manifest to disk atomically. */
|
|
36
|
+
export declare function persistManifest(manifestPath: string, manifest: WalkthroughManifest, completedAt: string): Promise<WalkthroughManifest>;
|
|
37
|
+
/** `complete --json` output: the canonical plus whichever extras exist. */
|
|
38
|
+
export declare function completeJsonPayload(canonical: CanonicalWalkthrough, extras: CompletionExtras): Record<string, unknown>;
|
|
39
|
+
/** Non-fatal provenance warnings; prints nothing for a clean audit. */
|
|
40
|
+
export declare function printProvenanceWarnings(audit: ProvenanceAudit): void;
|
|
41
|
+
/** Width and height from a PNG's IHDR chunk; null if it is not a PNG. */
|
|
42
|
+
export declare function pngSize(head: Buffer): {
|
|
43
|
+
width: number;
|
|
44
|
+
height: number;
|
|
45
|
+
} | null;
|
|
46
|
+
/**
|
|
47
|
+
* Is a screenshot `width` px wide consistent with a viewport `expected`
|
|
48
|
+
* CSS px wide? At 1× within 20%; at a 2× or 3× device pixel ratio the
|
|
49
|
+
* width is an exact multiple, so within 5% — wide enough for a scrollbar,
|
|
50
|
+
* narrow enough that a 1280 px desktop shot never passes as a 3× phone.
|
|
51
|
+
*/
|
|
52
|
+
export declare function screenshotFitsViewport(width: number, expected: number): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* A warning when the run's first screenshot is not the width of the
|
|
55
|
+
* device its persona uses — the browser was left at another persona's
|
|
56
|
+
* size. Null when the run recorded no viewport, has no screenshots, or
|
|
57
|
+
* the sizes agree. Never fatal.
|
|
58
|
+
*/
|
|
59
|
+
export declare function screenshotSizeWarning(runDirPath: string, viewport: RunViewport | null): Promise<string | null>;
|
|
60
|
+
export interface ProvenanceAudit {
|
|
61
|
+
verified: boolean;
|
|
62
|
+
warnings: string[];
|
|
63
|
+
step_count: number;
|
|
64
|
+
duration_seconds: number | null;
|
|
65
|
+
avg_step_interval_seconds: number | null;
|
|
66
|
+
uniform_intervals: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Audit steps for suspicious timing anomalies that indicate programmatic batch
|
|
70
|
+
* generation (scripts, mocks) rather than interactive human/LLM persona execution.
|
|
71
|
+
*/
|
|
72
|
+
export declare function auditStepProvenance(steps: Array<{
|
|
73
|
+
timestamp?: string;
|
|
74
|
+
action?: string;
|
|
75
|
+
step_number?: number;
|
|
76
|
+
}>): ProvenanceAudit;
|
|
77
|
+
/** Strictly validate runtime canonical structure against the protocol schema. */
|
|
78
|
+
export declare function validateCanonicalWalkthrough(canonical: unknown): CanonicalWalkthrough;
|
|
79
|
+
/**
|
|
80
|
+
* Read recorded judge verdicts (if present) and overlay them onto the canonical
|
|
81
|
+
* walkthrough for report markdown rendering.
|
|
82
|
+
*/
|
|
83
|
+
export declare function applyRecordedVerdicts(canonical: CanonicalWalkthrough, runDirPath: string): Promise<CanonicalWalkthrough>;
|
|
84
|
+
/** Persist canonical.json to disk atomically. */
|
|
85
|
+
export declare function persistCanonical(runDirPath: string, canonical: CanonicalWalkthrough): Promise<string>;
|
|
86
|
+
/** Persist report.md to disk atomically. */
|
|
87
|
+
export declare function persistReport(runDirPath: string, canonical: CanonicalWalkthrough): Promise<string>;
|
|
88
|
+
/**
|
|
89
|
+
* Build canonical.json (with the verification delta) and report.md for a
|
|
90
|
+
* run. The report keeps any verdicts already recorded by
|
|
91
|
+
* `evaluate-record`, so re-assembling after the judge (`--force`,
|
|
92
|
+
* `match-record`) does not drop them.
|
|
93
|
+
*/
|
|
94
|
+
export declare function assembleRun(projectRoot: string, runId: string, manifest: WalkthroughManifest, completedAt: string): Promise<{
|
|
95
|
+
canonical: CanonicalWalkthrough;
|
|
96
|
+
verification: VerificationSummary | null;
|
|
97
|
+
journeyDiff: JourneyDiff | null;
|
|
98
|
+
canonicalWithVerification: CanonicalWalkthrough & {
|
|
99
|
+
provenance_audit?: ProvenanceAudit;
|
|
100
|
+
};
|
|
101
|
+
canonicalPath: string;
|
|
102
|
+
reportPath: string;
|
|
103
|
+
}>;
|
|
104
|
+
/** One requested place, whether the run reached it, and what awaits there. */
|
|
105
|
+
export type RevisitReportPlace = RevisitPlaceCoverage & {
|
|
106
|
+
findings: Array<{
|
|
107
|
+
id: string;
|
|
108
|
+
title: string;
|
|
109
|
+
}>;
|
|
110
|
+
};
|
|
111
|
+
/** Coverage of the run's places to pass through, with finding titles. */
|
|
112
|
+
export interface RevisitReport {
|
|
113
|
+
requested: number;
|
|
114
|
+
reached: number;
|
|
115
|
+
places: RevisitReportPlace[];
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Did the run reach the places `start-run` asked it to pass through
|
|
119
|
+
* (manifest `revisit`)? Null when it asked for none. Local only: the
|
|
120
|
+
* cloud manifest has no field for it. Titles are for the person reading
|
|
121
|
+
* this output — the walker never saw them.
|
|
122
|
+
*/
|
|
123
|
+
export declare function revisitReport(projectRoot: string, runId: string, manifest: WalkthroughManifest): Promise<RevisitReport | null>;
|
|
124
|
+
/** Print "Re-check places: reached N of M — not reached: …". */
|
|
125
|
+
export declare function printRevisit(r: RevisitReport): void;
|
|
126
|
+
/**
|
|
127
|
+
* Print the delta against this scenario's previous completed run. Its
|
|
128
|
+
* counts are relative to that one run — "new" here means "not in that
|
|
129
|
+
* run", which is not the matcher's "first seen" (never recorded before)
|
|
130
|
+
* — so the heading says what it compares with.
|
|
131
|
+
*/
|
|
132
|
+
export declare function printVerification(verification: VerificationSummary): void;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readEntity } from "@iamu-dev/local-store";
|
|
2
|
+
import type { EntityType, ProjectConfig } from "@iamu-dev/protocol";
|
|
3
|
+
export interface ProjectContext {
|
|
4
|
+
projectRoot: string;
|
|
5
|
+
config: ProjectConfig;
|
|
6
|
+
}
|
|
7
|
+
export interface CloudContext extends ProjectContext {
|
|
8
|
+
apiKey: string;
|
|
9
|
+
apiUrl: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function commandError(message: string, opts?: {
|
|
12
|
+
json?: boolean | string;
|
|
13
|
+
}): void;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a run directory, reporting an unusable run id as a command
|
|
16
|
+
* error (message + exit code 1) instead of letting it reach the
|
|
17
|
+
* filesystem. Returns `null` once the error has been reported.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveRunDir(projectRoot: string, runId: string, opts?: {
|
|
20
|
+
json?: boolean;
|
|
21
|
+
}): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Last-resort handler for a rejection that escaped a command action.
|
|
24
|
+
* Prints one line — JSON-shaped when the invocation carried `--json` —
|
|
25
|
+
* and leaves a non-zero exit code behind. Without it, Commander's
|
|
26
|
+
* `parseAsync()` rejection reaches Node as an unhandled rejection: a
|
|
27
|
+
* stack trace at the user, and historically exit code 0.
|
|
28
|
+
*
|
|
29
|
+
* @param err - The value the command rejected with.
|
|
30
|
+
* @param argv - Invocation argv; only `--json` is read from it.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* await program.parseAsync().catch(reportFatalError);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function reportFatalError(err: unknown, argv?: readonly string[]): void;
|
|
38
|
+
export declare function resolveProject(opts?: {
|
|
39
|
+
json?: boolean | string;
|
|
40
|
+
}): Promise<ProjectContext | null>;
|
|
41
|
+
/**
|
|
42
|
+
* Resolves both project context and run directory path.
|
|
43
|
+
* Returns null if either fails (error already reported).
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveProjectAndRunDir(runId: string, opts?: {
|
|
46
|
+
cwd?: string;
|
|
47
|
+
json?: boolean;
|
|
48
|
+
}): Promise<{
|
|
49
|
+
projectRoot: string;
|
|
50
|
+
config: ProjectConfig;
|
|
51
|
+
runDirPath: string;
|
|
52
|
+
} | null>;
|
|
53
|
+
export declare function resolveCloudProject(opts?: {
|
|
54
|
+
json?: boolean | string;
|
|
55
|
+
}): Promise<CloudContext | null>;
|
|
56
|
+
export declare function safeReadEntity<T extends object = Record<string, unknown>>(projectRoot: string, type: EntityType, slug: string, opts?: {
|
|
57
|
+
json?: boolean | string;
|
|
58
|
+
}): Promise<Awaited<ReturnType<typeof readEntity<T>>> | null>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { IamuConfigError } from "@iamu-dev/protocol";
|
|
2
|
+
/**
|
|
3
|
+
* Production API URL, used when neither a flag, `IAMU_API_URL`, nor the
|
|
4
|
+
* project config names one.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const url = config.cloud_api_url ?? DEFAULT_API_URL;
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare const DEFAULT_API_URL = "https://app.iamu.dev";
|
|
12
|
+
/**
|
|
13
|
+
* Stored credentials, keyed by API URL. Values are left `unknown` on
|
|
14
|
+
* purpose: the file is user-editable, so every reader narrows.
|
|
15
|
+
*/
|
|
16
|
+
export type CredentialsStore = Record<string, unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Absolute path of the credentials file (`~/.iamu/credentials.json`).
|
|
19
|
+
*
|
|
20
|
+
* @returns The path; the file may not exist yet.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* console.log(`Tokens live in ${getCredentialsPath()}`);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function getCredentialsPath(): string;
|
|
28
|
+
/**
|
|
29
|
+
* The API URL a command talks to: the configured one (project config
|
|
30
|
+
* or flag), else `IAMU_API_URL`, else {@link DEFAULT_API_URL}. Empty
|
|
31
|
+
* strings count as unset.
|
|
32
|
+
*
|
|
33
|
+
* @param configured - URL from project config or a flag, if any.
|
|
34
|
+
* @returns The effective API URL.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* const apiUrl = resolveApiUrl(config.cloud_api_url);
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveApiUrl(configured?: string | null): string;
|
|
42
|
+
/**
|
|
43
|
+
* The credentials file exists but is not a JSON object. Reported instead
|
|
44
|
+
* of being treated as empty: the next login would otherwise overwrite
|
|
45
|
+
* every stored token without a word.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* try {
|
|
50
|
+
* await readCredentialsStore();
|
|
51
|
+
* } catch (err) {
|
|
52
|
+
* if (err instanceof CredentialsFileError) console.error(err.message);
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export declare class CredentialsFileError extends IamuConfigError {
|
|
57
|
+
/**
|
|
58
|
+
* @param path - The unreadable credentials file.
|
|
59
|
+
* @param reason - What is wrong with it.
|
|
60
|
+
* @param cause - Underlying parse error, if any.
|
|
61
|
+
*/
|
|
62
|
+
constructor(path: string, reason: string, cause?: unknown);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Read the whole credentials store. A missing file is an empty store; a
|
|
66
|
+
* corrupt one throws {@link CredentialsFileError} so no caller writes
|
|
67
|
+
* over tokens it could not read.
|
|
68
|
+
*
|
|
69
|
+
* @returns The parsed store.
|
|
70
|
+
* @throws {@link CredentialsFileError} when the file is not a JSON object.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const store = await readCredentialsStore();
|
|
75
|
+
* delete store["https://api.iamu.dev"];
|
|
76
|
+
* await writeCredentialsStore(store);
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function readCredentialsStore(): Promise<CredentialsStore>;
|
|
80
|
+
/**
|
|
81
|
+
* Replace the credentials store. Written to a temp file with mode 0600
|
|
82
|
+
* and renamed into place, so a crash mid-write leaves the previous file
|
|
83
|
+
* intact and the tokens are never world-readable, even briefly. The
|
|
84
|
+
* parent directory is created with mode 0700.
|
|
85
|
+
*
|
|
86
|
+
* @param store - The full store to persist.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* const store = await readCredentialsStore();
|
|
91
|
+
* store[apiUrl] = { token, createdAt: new Date().toISOString() };
|
|
92
|
+
* await writeCredentialsStore(store);
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare function writeCredentialsStore(store: CredentialsStore): Promise<void>;
|
|
96
|
+
/** @internal Reset warned flag for unit testing. */
|
|
97
|
+
export declare function _resetWarnedUnreadableStoreForTesting(): void;
|
|
98
|
+
/**
|
|
99
|
+
* Token for `apiUrl`: `IAMU_TOKEN`, then `IAMU_API_KEY`, then the entry
|
|
100
|
+
* for that URL in the credentials file. A corrupt credentials file is
|
|
101
|
+
* reported once on stderr (with the recovery step) and treated as no
|
|
102
|
+
* token.
|
|
103
|
+
*
|
|
104
|
+
* Synchronous because it sits on hot paths (MCP tool handlers, status).
|
|
105
|
+
*
|
|
106
|
+
* @param apiUrl - API URL the token must belong to; defaults via
|
|
107
|
+
* {@link resolveApiUrl}.
|
|
108
|
+
* @returns The token, or `null` when none is available.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* const token = resolveApiKey(config.cloud_api_url);
|
|
113
|
+
* if (!token) console.error("Run iamu auth login");
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare function resolveApiKey(apiUrl?: string | null): string | null;
|
|
117
|
+
/**
|
|
118
|
+
* True for hostnames that never leave the machine.
|
|
119
|
+
*
|
|
120
|
+
* @param hostname - `URL.hostname` (IPv6 arrives bracketed).
|
|
121
|
+
* @returns Whether the host is loopback.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* isLoopbackHost(new URL("http://[::1]:3000").hostname); // true
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
export declare function isLoopbackHost(hostname: string): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* Refuse an API URL that would send the bearer token in cleartext:
|
|
131
|
+
* anything but `https://`, except plain `http://` to a loopback host
|
|
132
|
+
* (the local cloud stack).
|
|
133
|
+
*
|
|
134
|
+
* @param url - Candidate API URL.
|
|
135
|
+
* @param source - Where it came from, for the error (`--url`,
|
|
136
|
+
* `IAMU_API_URL`, ...).
|
|
137
|
+
* @throws {@link IamuValidationError} when the URL is malformed or insecure.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* assertSecureApiUrl(process.env.IAMU_API_URL ?? DEFAULT_API_URL, "IAMU_API_URL");
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export declare function assertSecureApiUrl(url: string, source: string): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { OutlineFrontmatter, ScenarioFrontmatter } from "@iamu-dev/protocol";
|
|
2
|
+
export interface ChangedFilesResult {
|
|
3
|
+
baseRef: string;
|
|
4
|
+
files: string[];
|
|
5
|
+
}
|
|
6
|
+
/** Resolve changed files against a git base ref (e.g. origin/main, HEAD~1). */
|
|
7
|
+
export declare function getChangedFiles(projectRoot: string, explicitRef?: string | boolean): ChangedFilesResult | null;
|
|
8
|
+
/** Extract matching tokens from a scenario and its outline. */
|
|
9
|
+
export declare function extractScenarioKeywords(scenario: ScenarioFrontmatter, outline?: OutlineFrontmatter): string[];
|
|
10
|
+
/** Checks whether any changed file matches the scenario's keywords or path. */
|
|
11
|
+
export declare function matchesChangedFiles(changedFiles: string[], scenario: ScenarioFrontmatter, outline?: OutlineFrontmatter): boolean;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface DoctorCheck {
|
|
2
|
+
category: "runtime" | "browser" | "project" | "agent" | "cloud" | "target";
|
|
3
|
+
name: string;
|
|
4
|
+
status: "ok" | "warn" | "error";
|
|
5
|
+
message: string;
|
|
6
|
+
remedy?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface DoctorResult {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
checks: DoctorCheck[];
|
|
11
|
+
summary: {
|
|
12
|
+
ok: number;
|
|
13
|
+
warn: number;
|
|
14
|
+
error: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** Check if a TCP port is available or bound */
|
|
18
|
+
export declare function checkPortAvailable(port: number): Promise<boolean>;
|
|
19
|
+
/** Check CDP responsiveness on a port */
|
|
20
|
+
export declare function checkCdpResponsive(port: number): Promise<boolean>;
|
|
21
|
+
export declare function checkTargetHealth(targetUrl: string): Promise<DoctorCheck[]>;
|
|
22
|
+
export declare function checkProjectHarnesses(projectRoot: string): Promise<DoctorCheck[]>;
|
|
23
|
+
export declare function checkProjectTestabilityContract(projectRoot: string): Promise<{
|
|
24
|
+
checks: DoctorCheck[];
|
|
25
|
+
targetUrl?: string;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function runDoctorChecks(projectRoot?: string, opts?: {
|
|
28
|
+
target?: string;
|
|
29
|
+
}): Promise<DoctorResult>;
|
|
30
|
+
export declare function doctor(opts?: {
|
|
31
|
+
json?: boolean;
|
|
32
|
+
target?: string;
|
|
33
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type CanonicalWalkthrough } from "@iamu-dev/protocol";
|
|
2
|
+
/** What `verdicts.json` holds, as far as the report needs it. */
|
|
3
|
+
export interface RecordedVerdicts {
|
|
4
|
+
verdicts: Array<{
|
|
5
|
+
human_test_id: string;
|
|
6
|
+
verdict: string;
|
|
7
|
+
reasoning: string;
|
|
8
|
+
grounding_step_ids: string[];
|
|
9
|
+
grounding_finding_ids: string[];
|
|
10
|
+
}>;
|
|
11
|
+
overall?: {
|
|
12
|
+
answer: string;
|
|
13
|
+
reasoning: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A copy of `canonical` with the judge's verdicts filled in. canonical.json
|
|
18
|
+
* itself never carries them (its writer is `complete`); the report does.
|
|
19
|
+
*/
|
|
20
|
+
export declare function applyVerdicts(canonical: CanonicalWalkthrough, recorded: RecordedVerdicts): CanonicalWalkthrough;
|
|
21
|
+
export declare function evaluate(runId: string, opts?: {
|
|
22
|
+
json?: boolean;
|
|
23
|
+
promptFile?: string;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
export declare function evaluateRecord(runId: string, opts: {
|
|
26
|
+
file: string;
|
|
27
|
+
json?: boolean;
|
|
28
|
+
yes?: boolean;
|
|
29
|
+
prompt?: boolean;
|
|
30
|
+
view?: boolean;
|
|
31
|
+
push?: boolean;
|
|
32
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-only crawl behind `iamu explore`.
|
|
3
|
+
*
|
|
4
|
+
* Breadth-first from the start URL: on every surface, try every visible
|
|
5
|
+
* link and button once, and see where it leads. A surface is a page
|
|
6
|
+
* (keyed by its templated URL, see `explorePlaceKey`) or a view a click
|
|
7
|
+
* switched to on the same URL (keyed by its headings). Every surface is
|
|
8
|
+
* reached by replaying its path from the start, so the crawl does not
|
|
9
|
+
* depend on what the previous click left behind, and two crawls of one
|
|
10
|
+
* build should produce the same map.
|
|
11
|
+
*
|
|
12
|
+
* Read-only is enforced twice:
|
|
13
|
+
* - Controls whose name or link reads like a write (delete, pay, send,
|
|
14
|
+
* save, log out …), form submits, downloads and other origins are
|
|
15
|
+
* never clicked. Nothing is typed into a field.
|
|
16
|
+
* - Every request that is not GET/HEAD/OPTIONS is aborted before it
|
|
17
|
+
* leaves the browser, and recorded on the action that caused it.
|
|
18
|
+
*
|
|
19
|
+
* Dialogs are dismissed (`confirm()` answers no) and popups closed.
|
|
20
|
+
* WebSocket messages are not guarded; a page controlled by a service
|
|
21
|
+
* worker (whose requests the guard cannot see) is refused.
|
|
22
|
+
*/
|
|
23
|
+
import { type ExploreBudget, type ExploreStats, type ExploreSurface } from "@iamu-dev/local-store";
|
|
24
|
+
import type { Page } from "playwright-core";
|
|
25
|
+
/**
|
|
26
|
+
* Options for {@link crawl}.
|
|
27
|
+
*
|
|
28
|
+
* @public
|
|
29
|
+
*/
|
|
30
|
+
export interface CrawlOptions {
|
|
31
|
+
startUrl: string;
|
|
32
|
+
budget: ExploreBudget;
|
|
33
|
+
/** Extra patterns: a control whose name or link matches is never tried. */
|
|
34
|
+
deny?: RegExp[];
|
|
35
|
+
/** Longest wait for the page to settle after an action. */
|
|
36
|
+
settleMs?: number;
|
|
37
|
+
/** One line per new surface, for progress output. */
|
|
38
|
+
log?: (line: string) => void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* What {@link crawl} found.
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
*/
|
|
45
|
+
export interface CrawlResult {
|
|
46
|
+
surfaces: ExploreSurface[];
|
|
47
|
+
stats: ExploreStats;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Crawl the product read-only from `opts.startUrl`.
|
|
51
|
+
*
|
|
52
|
+
* @param page - A page of its own; the crawl navigates it freely and
|
|
53
|
+
* installs a request guard on it.
|
|
54
|
+
* @param opts - Start URL, budget, extra deny patterns.
|
|
55
|
+
* @returns The surfaces found and counts.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const { surfaces, stats } = await crawl(page, {
|
|
60
|
+
* startUrl: "http://localhost:3000/",
|
|
61
|
+
* budget: { max_surfaces: 40, max_actions: 300, max_depth: 6 },
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*
|
|
65
|
+
* @public
|
|
66
|
+
*/
|
|
67
|
+
export declare function crawl(page: Page, opts: CrawlOptions): Promise<CrawlResult>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** Parsed options for `iamu explore [url]`. */
|
|
2
|
+
export interface ExploreOptions {
|
|
3
|
+
maxSurfaces?: string;
|
|
4
|
+
maxActions?: string;
|
|
5
|
+
maxDepth?: string;
|
|
6
|
+
deny?: string[];
|
|
7
|
+
viewport?: string;
|
|
8
|
+
attach?: boolean;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `iamu explore [url]`: crawl the product read-only and write a map.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* await exploreRun("http://localhost:3000/", { maxSurfaces: "20" });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function exploreRun(url: string | undefined, opts: ExploreOptions): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* `iamu explore list`.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* await exploreList({ json: true });
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function exploreList(opts: {
|
|
29
|
+
json?: boolean;
|
|
30
|
+
}): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* `iamu explore coverage [map]`.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* await exploreCoverageCommand(undefined, {});
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function exploreCoverageCommand(mapId: string | undefined, opts: {
|
|
40
|
+
json?: boolean;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* `iamu explore diff [a] [b]` — default: the two latest maps.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* await exploreDiffCommand(undefined, undefined, { json: true });
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function exploreDiffCommand(a: string | undefined, b: string | undefined, opts: {
|
|
51
|
+
json?: boolean;
|
|
52
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { HostAdapter } from "../adapters/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The setup skill as the user will see it. With the Iamu plugin enabled,
|
|
4
|
+
* Claude Code has `/iamu:init` and no `iamu-setup`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function setupCommand(projectRoot: string, hosts: HostAdapter[]): string;
|
|
7
|
+
export interface InitOptions {
|
|
8
|
+
name?: string;
|
|
9
|
+
yes?: boolean;
|
|
10
|
+
json?: boolean;
|
|
11
|
+
cloud?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Scaffold `iamu/` and install skills for the detected hosts.
|
|
15
|
+
*/
|
|
16
|
+
export declare function init(opts?: InitOptions | string): Promise<void>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type GuidanceRule, type RevisitPlace } from "@iamu-dev/local-store";
|
|
2
|
+
import { type RunViewport, type ScenarioState } from "@iamu-dev/protocol";
|
|
3
|
+
/** "The browser is sized as a phone screen, 390×844." */
|
|
4
|
+
export declare function viewportLine(v: RunViewport): string;
|
|
5
|
+
interface WalkerPromptParts {
|
|
6
|
+
targetUrl: string | null;
|
|
7
|
+
persona: {
|
|
8
|
+
name: string;
|
|
9
|
+
role: string;
|
|
10
|
+
disposition: string | null;
|
|
11
|
+
background: string | null;
|
|
12
|
+
};
|
|
13
|
+
outline: {
|
|
14
|
+
title: string;
|
|
15
|
+
tension: unknown;
|
|
16
|
+
narrative: unknown;
|
|
17
|
+
};
|
|
18
|
+
brief: string | null;
|
|
19
|
+
access: {
|
|
20
|
+
project: string | null;
|
|
21
|
+
persona: string | null;
|
|
22
|
+
};
|
|
23
|
+
methodology: string;
|
|
24
|
+
dismissed: string[];
|
|
25
|
+
/** Active tester guidance in the scenario's scope. */
|
|
26
|
+
guidance?: GuidanceRule[];
|
|
27
|
+
/** Where fixes awaiting a re-run were seen — places only, no findings. */
|
|
28
|
+
revisit?: RevisitPlace[];
|
|
29
|
+
scenarioSlug: string;
|
|
30
|
+
runId: string;
|
|
31
|
+
runDirPath: string;
|
|
32
|
+
projectRoot: string;
|
|
33
|
+
surface: string;
|
|
34
|
+
/** The run's viewport (`start-run`, from persona tags), if any. */
|
|
35
|
+
viewport?: RunViewport | null;
|
|
36
|
+
/** Scenario environment state and semantic approximation guidance */
|
|
37
|
+
state?: ScenarioState | null;
|
|
38
|
+
/** Product domain and regulatory context from context.yml */
|
|
39
|
+
context?: string | null;
|
|
40
|
+
/** Untestable execution boundaries from testability.md */
|
|
41
|
+
untestableBoundaries?: string[] | null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extracts bullet points from a markdown "## Untestable Boundaries" section.
|
|
45
|
+
*/
|
|
46
|
+
export declare function extractUntestableBoundaries(body: string): string[];
|
|
47
|
+
/**
|
|
48
|
+
* The places-to-pass-through section: where this scenario's fixes
|
|
49
|
+
* awaiting a re-run were observed, framed as part of the persona's own
|
|
50
|
+
* route. It carries URLs and screen names only — never a finding's
|
|
51
|
+
* title, type, severity or any hint of what was wrong, so the walker
|
|
52
|
+
* judges each place fresh (the same reason it never sees human tests).
|
|
53
|
+
* Empty when nothing awaits, so those prompts stay as they were.
|
|
54
|
+
*/
|
|
55
|
+
export declare function revisitSection(places: readonly RevisitPlace[]): string[];
|
|
56
|
+
/**
|
|
57
|
+
* The walker subagent's whole prompt — persona, situation, brief, access,
|
|
58
|
+
* driving surface, methodology, and the run-directory contract (steps,
|
|
59
|
+
* screenshots, findings, summary.json). Composed here so every host
|
|
60
|
+
* hands its walker the same thing instead of assembling it by hand.
|
|
61
|
+
*/
|
|
62
|
+
export declare function composeWalkerPrompt(p: WalkerPromptParts): string;
|
|
63
|
+
export declare function instructionsWalk(opts: {
|
|
64
|
+
scenario: string;
|
|
65
|
+
run?: string;
|
|
66
|
+
surface?: string;
|
|
67
|
+
json?: boolean;
|
|
68
|
+
}): Promise<void>;
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Print the matcher's input bundle: this run's findings, the scenario's
|
|
3
|
+
* earlier canonical findings, this run's steps, and the prompt.
|
|
4
|
+
*/
|
|
5
|
+
export declare function match(runId: string, opts?: {
|
|
6
|
+
json?: boolean;
|
|
7
|
+
promptFile?: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
/** Record the matcher's answer and re-derive the run's delta and report. */
|
|
10
|
+
export declare function matchRecord(runId: string, opts: {
|
|
11
|
+
file: string;
|
|
12
|
+
json?: boolean;
|
|
13
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write or update the `iamu-sync` entry in an MCP config file.
|
|
3
|
+
* Merges with existing content — does not clobber other servers.
|
|
4
|
+
* Throws if existing file contains invalid JSON (avoids silent data loss).
|
|
5
|
+
*/
|
|
6
|
+
export declare function writeSyncMcpEntry(mcpPath: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Check if an MCP config file has an `iamu-sync` entry.
|
|
9
|
+
*/
|
|
10
|
+
export declare function hasSyncMcpEntry(parsed: Record<string, unknown>, mcpPath: string): boolean;
|