@iamu-dev/iamu 0.2.0-beta.3 → 0.2.0-beta.5
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/dist/bin.js +120 -25
- package/dist/index.js +120 -25
- package/dist/templates/skills/iamu-findings.md +27 -29
- package/dist/templates/skills/iamu-new.md +42 -43
- package/dist/templates/skills/iamu-propose.md +34 -18
- package/dist/templates/skills/iamu-run.md +92 -40
- package/dist/templates/skills/iamu-setup.md +15 -10
- package/dist/templates/skills/iamu-status.md +21 -14
- package/package.json +3 -3
package/dist/bin.js
CHANGED
|
@@ -11896,7 +11896,7 @@ var init_credentials = __esm({
|
|
|
11896
11896
|
"use strict";
|
|
11897
11897
|
init_dist2();
|
|
11898
11898
|
init_dist();
|
|
11899
|
-
DEFAULT_API_URL = "https://
|
|
11899
|
+
DEFAULT_API_URL = "https://app.iamu.dev";
|
|
11900
11900
|
CredentialsFileError = class extends IamuConfigError {
|
|
11901
11901
|
/**
|
|
11902
11902
|
* @param path - The unreadable credentials file.
|
|
@@ -11993,7 +11993,7 @@ async function resolveCloudProject(opts) {
|
|
|
11993
11993
|
commandError("Not cloud-linked. Run `iamu auth login` to connect.", opts);
|
|
11994
11994
|
return null;
|
|
11995
11995
|
}
|
|
11996
|
-
const apiUrl = ctx.config.cloud_api_url ??
|
|
11996
|
+
const apiUrl = ctx.config.cloud_api_url ?? DEFAULT_API_URL;
|
|
11997
11997
|
try {
|
|
11998
11998
|
assertSecureApiUrl(apiUrl, "cloud_api_url");
|
|
11999
11999
|
} catch (err) {
|
|
@@ -13502,12 +13502,24 @@ async function browserLogin(apiUrl, opts, t) {
|
|
|
13502
13502
|
chalk8.red(`
|
|
13503
13503
|
Auth session expired or failed (HTTP ${result.status}).`)
|
|
13504
13504
|
);
|
|
13505
|
+
console.error(
|
|
13506
|
+
chalk8.dim(" Re-run `iamu auth login` to start a new login session.\n")
|
|
13507
|
+
);
|
|
13505
13508
|
process.exitCode = 1;
|
|
13506
13509
|
return null;
|
|
13507
13510
|
}
|
|
13508
13511
|
if (result.kind === "timeout") {
|
|
13509
13512
|
s.stop("Authentication timed out.");
|
|
13510
|
-
console.error(
|
|
13513
|
+
console.error(
|
|
13514
|
+
chalk8.red(
|
|
13515
|
+
"\n Authentication timed out (no approval received within 2 minutes)."
|
|
13516
|
+
)
|
|
13517
|
+
);
|
|
13518
|
+
console.error(
|
|
13519
|
+
chalk8.dim(
|
|
13520
|
+
" \u2022 Complete browser authorization faster, or authenticate non-interactively with --token <key>.\n \u2022 Local setup is unaffected \u2014 re-run `iamu auth login` anytime.\n"
|
|
13521
|
+
)
|
|
13522
|
+
);
|
|
13511
13523
|
process.exitCode = 1;
|
|
13512
13524
|
return null;
|
|
13513
13525
|
}
|
|
@@ -13533,7 +13545,12 @@ async function startAuthSession(apiUrl, timeoutMs) {
|
|
|
13533
13545
|
if (!res.ok) {
|
|
13534
13546
|
console.error(
|
|
13535
13547
|
chalk8.red(
|
|
13536
|
-
` Failed to start auth session: ${res.text || `HTTP ${res.status}`}`
|
|
13548
|
+
` Failed to start auth session at ${apiUrl}: ${res.text || `HTTP ${res.status}`}`
|
|
13549
|
+
)
|
|
13550
|
+
);
|
|
13551
|
+
console.error(
|
|
13552
|
+
chalk8.dim(
|
|
13553
|
+
" \u2022 The cloud service may be experiencing downtime or maintenance.\n \u2022 Local setup is unaffected; continue with local workflows or retry later with `iamu auth login`.\n"
|
|
13537
13554
|
)
|
|
13538
13555
|
);
|
|
13539
13556
|
process.exitCode = 1;
|
|
@@ -13547,7 +13564,13 @@ async function startAuthSession(apiUrl, timeoutMs) {
|
|
|
13547
13564
|
return { sessionId: data.sessionId, loginUrl: data.loginUrl };
|
|
13548
13565
|
} catch (err) {
|
|
13549
13566
|
console.error(
|
|
13550
|
-
chalk8.red(
|
|
13567
|
+
chalk8.red(` Cannot reach Iamu Cloud (${apiUrl}).`) + chalk8.dim(`
|
|
13568
|
+
Reason: ${errorMessage(err)}`)
|
|
13569
|
+
);
|
|
13570
|
+
console.error(
|
|
13571
|
+
chalk8.dim(
|
|
13572
|
+
"\n \u2022 Check your internet connection or proxy settings.\n \u2022 If using a custom instance, pass --url <api-url> or set IAMU_API_URL.\n \u2022 Local setup is unaffected; continue with local workflows or retry later with `iamu auth login`.\n"
|
|
13573
|
+
)
|
|
13551
13574
|
);
|
|
13552
13575
|
process.exitCode = 1;
|
|
13553
13576
|
return null;
|
|
@@ -16978,6 +17001,35 @@ function printStep(opts, record, projectRoot) {
|
|
|
16978
17001
|
}
|
|
16979
17002
|
}
|
|
16980
17003
|
async function browseStep(args, opts, driver) {
|
|
17004
|
+
if (opts.stepFile) {
|
|
17005
|
+
try {
|
|
17006
|
+
let raw;
|
|
17007
|
+
if (opts.stepFile === "-") {
|
|
17008
|
+
raw = readFileSync6(0, "utf8");
|
|
17009
|
+
} else {
|
|
17010
|
+
raw = readFileSync6(opts.stepFile, "utf8");
|
|
17011
|
+
}
|
|
17012
|
+
const data = JSON.parse(raw);
|
|
17013
|
+
if (data.run && typeof data.run === "string") opts.run = data.run;
|
|
17014
|
+
if (data.action && typeof data.action === "string")
|
|
17015
|
+
opts.action = data.action;
|
|
17016
|
+
if (data.note && typeof data.note === "string") opts.note = data.note;
|
|
17017
|
+
if (data.surface && typeof data.surface === "string")
|
|
17018
|
+
opts.surface = data.surface;
|
|
17019
|
+
if (args.length === 0 && data.cmd) {
|
|
17020
|
+
if (Array.isArray(data.cmd)) {
|
|
17021
|
+
args = data.cmd.map(String);
|
|
17022
|
+
} else if (typeof data.cmd === "string") {
|
|
17023
|
+
args = data.cmd.trim().split(/\s+/);
|
|
17024
|
+
}
|
|
17025
|
+
}
|
|
17026
|
+
} catch (err) {
|
|
17027
|
+
return fail(
|
|
17028
|
+
`Failed to read step payload from ${opts.stepFile}: ${err.message}`,
|
|
17029
|
+
opts
|
|
17030
|
+
);
|
|
17031
|
+
}
|
|
17032
|
+
}
|
|
16981
17033
|
if (!opts.run)
|
|
16982
17034
|
return fail("--run <run-id> is required for browse step.", opts);
|
|
16983
17035
|
if (!opts.action) {
|
|
@@ -18393,7 +18445,8 @@ function defaultFrontmatter(type2, id, slug, name, opts) {
|
|
|
18393
18445
|
...base,
|
|
18394
18446
|
name,
|
|
18395
18447
|
role: opts.role ?? "TODO",
|
|
18396
|
-
...opts.disposition ? { disposition: opts.disposition } : {}
|
|
18448
|
+
...opts.disposition ? { disposition: opts.disposition } : {},
|
|
18449
|
+
...opts.access ? { access: opts.access } : {}
|
|
18397
18450
|
};
|
|
18398
18451
|
case "outline":
|
|
18399
18452
|
return { ...base, title: name, ...description };
|
|
@@ -18462,7 +18515,7 @@ async function newEntity(type2, opts) {
|
|
|
18462
18515
|
}
|
|
18463
18516
|
const id = randomUUID9();
|
|
18464
18517
|
const frontmatter = defaultFrontmatter(entityType, id, slug, opts.name, opts);
|
|
18465
|
-
const body = "";
|
|
18518
|
+
const body = opts.body ?? opts.narrative ?? "";
|
|
18466
18519
|
try {
|
|
18467
18520
|
const record = await writeEntity(
|
|
18468
18521
|
projectRoot,
|
|
@@ -19433,8 +19486,21 @@ async function evaluate(runId, opts) {
|
|
|
19433
19486
|
)
|
|
19434
19487
|
};
|
|
19435
19488
|
const prompt = composeJudgePrompt(input);
|
|
19489
|
+
const promptFilePath = opts?.promptFile ?? path25.join(runDirPath, "judge_prompt.md");
|
|
19490
|
+
await fs25.writeFile(promptFilePath, prompt, "utf8");
|
|
19436
19491
|
if (opts?.json) {
|
|
19437
|
-
console.log(
|
|
19492
|
+
console.log(
|
|
19493
|
+
JSON.stringify(
|
|
19494
|
+
{
|
|
19495
|
+
...input,
|
|
19496
|
+
prompt_file: path25.relative(projectRoot, promptFilePath),
|
|
19497
|
+
prompt_file_abs: path25.resolve(promptFilePath),
|
|
19498
|
+
judge_prompt: prompt
|
|
19499
|
+
},
|
|
19500
|
+
null,
|
|
19501
|
+
2
|
|
19502
|
+
)
|
|
19503
|
+
);
|
|
19438
19504
|
return;
|
|
19439
19505
|
}
|
|
19440
19506
|
console.log(prompt);
|
|
@@ -19526,7 +19592,7 @@ ${formatIssues(fileResult.error)}`,
|
|
|
19526
19592
|
runId,
|
|
19527
19593
|
validatedVerdicts
|
|
19528
19594
|
);
|
|
19529
|
-
const cloudInfo = await pushRunToCloud(projectRoot, runId);
|
|
19595
|
+
const cloudInfo = opts?.push === false ? void 0 : await pushRunToCloud(projectRoot, runId);
|
|
19530
19596
|
if (opts?.json) {
|
|
19531
19597
|
console.log(
|
|
19532
19598
|
JSON.stringify(
|
|
@@ -19770,7 +19836,7 @@ async function collectCompletionExtras(run, opts) {
|
|
|
19770
19836
|
parseRunViewport(manifest.viewport)
|
|
19771
19837
|
);
|
|
19772
19838
|
const codeWarning = opts?.force ? null : codeChangedWarning(manifest.build, detectWorktreeState(projectRoot));
|
|
19773
|
-
const cloudInfo = await pushRunToCloud(projectRoot, runId);
|
|
19839
|
+
const cloudInfo = opts?.push === false ? void 0 : await pushRunToCloud(projectRoot, runId);
|
|
19774
19840
|
return { revisit, viewportWarning, codeWarning, cloudInfo };
|
|
19775
19841
|
}
|
|
19776
19842
|
function completeJsonPayload(canonical, extras) {
|
|
@@ -20223,9 +20289,28 @@ async function match(runId, opts) {
|
|
|
20223
20289
|
);
|
|
20224
20290
|
const needed = input.current.length > 0 && (input.prior.length > 0 || (input.guidance ?? []).length > 0);
|
|
20225
20291
|
const prompt = needed ? composeMatchPrompt(input) : null;
|
|
20292
|
+
const promptFilePath = opts?.promptFile ?? path27.join(runDirPath, "match_prompt.md");
|
|
20293
|
+
if (prompt) {
|
|
20294
|
+
await fs27.writeFile(promptFilePath, prompt, "utf8");
|
|
20295
|
+
} else {
|
|
20296
|
+
try {
|
|
20297
|
+
await fs27.unlink(promptFilePath);
|
|
20298
|
+
} catch {
|
|
20299
|
+
}
|
|
20300
|
+
}
|
|
20226
20301
|
if (opts?.json) {
|
|
20227
20302
|
console.log(
|
|
20228
|
-
JSON.stringify(
|
|
20303
|
+
JSON.stringify(
|
|
20304
|
+
{
|
|
20305
|
+
...input,
|
|
20306
|
+
needed,
|
|
20307
|
+
prompt_file: prompt ? path27.relative(ctx.projectRoot, promptFilePath) : null,
|
|
20308
|
+
prompt_file_abs: prompt ? path27.resolve(promptFilePath) : null,
|
|
20309
|
+
match_prompt: prompt
|
|
20310
|
+
},
|
|
20311
|
+
null,
|
|
20312
|
+
2
|
|
20313
|
+
)
|
|
20229
20314
|
);
|
|
20230
20315
|
return;
|
|
20231
20316
|
}
|
|
@@ -20464,7 +20549,7 @@ function registerCloudCommands(program2) {
|
|
|
20464
20549
|
"Connect to local cloud stack (default port: 3000)"
|
|
20465
20550
|
).addOption(
|
|
20466
20551
|
new Option("-s, --staging", "Connect to staging cloud stack").hideHelp()
|
|
20467
|
-
).option("-t, --token <token>", "Authenticate directly with API token / key").option("--web-url <url>", "Custom web dashboard URL").option("--url <api-url>", "API URL (default: https://
|
|
20552
|
+
).option("-t, --token <token>", "Authenticate directly with API token / key").option("--web-url <url>", "Custom web dashboard URL").option("--url <api-url>", "API URL (default: https://app.iamu.dev)").option("-y, --yes", "Accept default project without interactive selection").option(
|
|
20468
20553
|
"--project <project-id>",
|
|
20469
20554
|
"Cloud project ID to link to, or `new` to create one. Required in a non-interactive shell when cloud projects exist"
|
|
20470
20555
|
).option("--no-browser", "Do not launch browser automatically").addHelpText(
|
|
@@ -20620,6 +20705,9 @@ function registerProjectCommands(program2) {
|
|
|
20620
20705
|
program2.command("new <type>").helpGroup("Project:").description(
|
|
20621
20706
|
"Create a new entity (persona, outline, capability, source, scenario)"
|
|
20622
20707
|
).requiredOption("--name <name>", "Entity name").option("--slug <slug>", "Custom entity slug (defaults to slugified name)").option("--role <role>", "Role description (persona only)").option("--disposition <text>", "Disposition / attitude (persona only)").option(
|
|
20708
|
+
"--access <role>",
|
|
20709
|
+
"Access role or testing account key (persona only)"
|
|
20710
|
+
).option("--body <text>", "Markdown body / narrative content").option("--narrative <text>", "Alias for --body").option(
|
|
20623
20711
|
"--description <text>",
|
|
20624
20712
|
"One-line description (capability, outline)"
|
|
20625
20713
|
).option("--outline <slug>", "Outline slug (scenario only)").option("--persona <slug>", "Persona slug (scenario only)").option(
|
|
@@ -20696,7 +20784,10 @@ function registerWalkthroughCommands(program2) {
|
|
|
20696
20784
|
).option(
|
|
20697
20785
|
"--run <run-id>",
|
|
20698
20786
|
"Run ID to size browser (start) or record step into (step)"
|
|
20699
|
-
).option("--action <text>", "Action description (step only)").option("--note <text>", "Persona inner monologue / reasoning (step only)").option("--surface <name>", "Screen or surface name (step only)").option(
|
|
20787
|
+
).option("--action <text>", "Action description (step only)").option("--note <text>", "Persona inner monologue / reasoning (step only)").option("--surface <name>", "Screen or surface name (step only)").option(
|
|
20788
|
+
"--step-file <path>",
|
|
20789
|
+
"Read step payload (action, note, cmd) from a JSON file or '-' for stdin (step only)"
|
|
20790
|
+
).option("--width <px>", "Window width (start)").option("--height <px>", "Window height (start)").option("--headless", "Run without a window (start)").option(
|
|
20700
20791
|
"--port <port>",
|
|
20701
20792
|
"CDP port (start), default 9333",
|
|
20702
20793
|
(value) => parsePortOption(value)
|
|
@@ -20772,9 +20863,9 @@ function registerWalkthroughCommands(program2) {
|
|
|
20772
20863
|
).option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--view", "Open results in browser immediately without prompt").option(
|
|
20773
20864
|
"--strict-provenance",
|
|
20774
20865
|
"Fail if steps show synthetic or programmatic timing anomalies"
|
|
20775
|
-
).addHelpText(
|
|
20866
|
+
).option("--no-push", "Skip pushing the run to Iamu Cloud").addHelpText(
|
|
20776
20867
|
"after",
|
|
20777
|
-
"\nExamples:\n $ iamu complete <run-id>\n $ iamu complete <run-id> --view\n $ iamu complete <run-id> --no-prompt\n $ iamu complete <run-id> --json\n $ iamu complete <run-id> --strict-provenance"
|
|
20868
|
+
"\nExamples:\n $ iamu complete <run-id>\n $ iamu complete <run-id> --view\n $ iamu complete <run-id> --no-prompt\n $ iamu complete <run-id> --no-push\n $ iamu complete <run-id> --json\n $ iamu complete <run-id> --strict-provenance"
|
|
20778
20869
|
).action(
|
|
20779
20870
|
async (runId, opts) => {
|
|
20780
20871
|
const { complete: complete2 } = await Promise.resolve().then(() => (init_complete(), complete_exports));
|
|
@@ -20783,23 +20874,27 @@ function registerWalkthroughCommands(program2) {
|
|
|
20783
20874
|
);
|
|
20784
20875
|
program2.command("match <run-id>").helpGroup("Walkthrough:").description(
|
|
20785
20876
|
"Compose the prompt that links this run's findings to earlier ones"
|
|
20786
|
-
).option("--json", "Output the match input bundle as JSON").
|
|
20787
|
-
|
|
20788
|
-
|
|
20789
|
-
|
|
20877
|
+
).option("--json", "Output the match input bundle as JSON").option("--prompt-file <path>", "Write the generated prompt to a file").action(
|
|
20878
|
+
async (runId, opts) => {
|
|
20879
|
+
const { match: match2 } = await Promise.resolve().then(() => (init_match(), match_exports));
|
|
20880
|
+
await match2(runId, opts);
|
|
20881
|
+
}
|
|
20882
|
+
);
|
|
20790
20883
|
program2.command("match-record <run-id>").helpGroup("Walkthrough:").description(
|
|
20791
20884
|
"Record finding matches and re-derive the run's since-last-run delta"
|
|
20792
20885
|
).requiredOption("--file <path>", "Path to matches JSON file").option("--json", "Output match results as JSON").action(async (runId, opts) => {
|
|
20793
20886
|
const { matchRecord: matchRecord2 } = await Promise.resolve().then(() => (init_match(), match_exports));
|
|
20794
20887
|
await matchRecord2(runId, opts);
|
|
20795
20888
|
});
|
|
20796
|
-
program2.command("evaluate <run-id>").helpGroup("Walkthrough:").description("Compose evaluation prompt for human-test questions").option("--json", "Output evaluation input bundle as JSON").
|
|
20797
|
-
|
|
20798
|
-
|
|
20799
|
-
|
|
20800
|
-
|
|
20889
|
+
program2.command("evaluate <run-id>").helpGroup("Walkthrough:").description("Compose evaluation prompt for human-test questions").option("--json", "Output evaluation input bundle as JSON").option("--prompt-file <path>", "Write the generated prompt to a file").action(
|
|
20890
|
+
async (runId, opts) => {
|
|
20891
|
+
const { evaluate: evaluate2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
|
|
20892
|
+
await evaluate2(runId, opts);
|
|
20893
|
+
}
|
|
20894
|
+
);
|
|
20895
|
+
program2.command("evaluate-record <run-id>").helpGroup("Walkthrough:").description("Record evaluation verdicts into the run's verdicts.json").requiredOption("--file <path>", "Path to verdicts JSON file").option("--json", "Output summary as JSON").option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--no-push", "Skip pushing the updated run to Iamu Cloud").option("--view", "Open results in browser immediately without prompt").addHelpText(
|
|
20801
20896
|
"after",
|
|
20802
|
-
"\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
|
|
20897
|
+
"\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --no-push\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
|
|
20803
20898
|
).action(
|
|
20804
20899
|
async (runId, opts) => {
|
|
20805
20900
|
const { evaluateRecord: evaluateRecord2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
|
package/dist/index.js
CHANGED
|
@@ -11968,7 +11968,7 @@ var init_credentials = __esm({
|
|
|
11968
11968
|
"use strict";
|
|
11969
11969
|
init_dist2();
|
|
11970
11970
|
init_dist();
|
|
11971
|
-
DEFAULT_API_URL = "https://
|
|
11971
|
+
DEFAULT_API_URL = "https://app.iamu.dev";
|
|
11972
11972
|
CredentialsFileError = class extends IamuConfigError {
|
|
11973
11973
|
/**
|
|
11974
11974
|
* @param path - The unreadable credentials file.
|
|
@@ -12118,7 +12118,7 @@ async function resolveCloudProject(opts) {
|
|
|
12118
12118
|
commandError("Not cloud-linked. Run `iamu auth login` to connect.", opts);
|
|
12119
12119
|
return null;
|
|
12120
12120
|
}
|
|
12121
|
-
const apiUrl = ctx.config.cloud_api_url ??
|
|
12121
|
+
const apiUrl = ctx.config.cloud_api_url ?? DEFAULT_API_URL;
|
|
12122
12122
|
try {
|
|
12123
12123
|
assertSecureApiUrl(apiUrl, "cloud_api_url");
|
|
12124
12124
|
} catch (err) {
|
|
@@ -13481,12 +13481,24 @@ async function browserLogin(apiUrl, opts, t) {
|
|
|
13481
13481
|
chalk8.red(`
|
|
13482
13482
|
Auth session expired or failed (HTTP ${result.status}).`)
|
|
13483
13483
|
);
|
|
13484
|
+
console.error(
|
|
13485
|
+
chalk8.dim(" Re-run `iamu auth login` to start a new login session.\n")
|
|
13486
|
+
);
|
|
13484
13487
|
process.exitCode = 1;
|
|
13485
13488
|
return null;
|
|
13486
13489
|
}
|
|
13487
13490
|
if (result.kind === "timeout") {
|
|
13488
13491
|
s.stop("Authentication timed out.");
|
|
13489
|
-
console.error(
|
|
13492
|
+
console.error(
|
|
13493
|
+
chalk8.red(
|
|
13494
|
+
"\n Authentication timed out (no approval received within 2 minutes)."
|
|
13495
|
+
)
|
|
13496
|
+
);
|
|
13497
|
+
console.error(
|
|
13498
|
+
chalk8.dim(
|
|
13499
|
+
" \u2022 Complete browser authorization faster, or authenticate non-interactively with --token <key>.\n \u2022 Local setup is unaffected \u2014 re-run `iamu auth login` anytime.\n"
|
|
13500
|
+
)
|
|
13501
|
+
);
|
|
13490
13502
|
process.exitCode = 1;
|
|
13491
13503
|
return null;
|
|
13492
13504
|
}
|
|
@@ -13512,7 +13524,12 @@ async function startAuthSession(apiUrl, timeoutMs) {
|
|
|
13512
13524
|
if (!res.ok) {
|
|
13513
13525
|
console.error(
|
|
13514
13526
|
chalk8.red(
|
|
13515
|
-
` Failed to start auth session: ${res.text || `HTTP ${res.status}`}`
|
|
13527
|
+
` Failed to start auth session at ${apiUrl}: ${res.text || `HTTP ${res.status}`}`
|
|
13528
|
+
)
|
|
13529
|
+
);
|
|
13530
|
+
console.error(
|
|
13531
|
+
chalk8.dim(
|
|
13532
|
+
" \u2022 The cloud service may be experiencing downtime or maintenance.\n \u2022 Local setup is unaffected; continue with local workflows or retry later with `iamu auth login`.\n"
|
|
13516
13533
|
)
|
|
13517
13534
|
);
|
|
13518
13535
|
process.exitCode = 1;
|
|
@@ -13526,7 +13543,13 @@ async function startAuthSession(apiUrl, timeoutMs) {
|
|
|
13526
13543
|
return { sessionId: data.sessionId, loginUrl: data.loginUrl };
|
|
13527
13544
|
} catch (err) {
|
|
13528
13545
|
console.error(
|
|
13529
|
-
chalk8.red(
|
|
13546
|
+
chalk8.red(` Cannot reach Iamu Cloud (${apiUrl}).`) + chalk8.dim(`
|
|
13547
|
+
Reason: ${errorMessage(err)}`)
|
|
13548
|
+
);
|
|
13549
|
+
console.error(
|
|
13550
|
+
chalk8.dim(
|
|
13551
|
+
"\n \u2022 Check your internet connection or proxy settings.\n \u2022 If using a custom instance, pass --url <api-url> or set IAMU_API_URL.\n \u2022 Local setup is unaffected; continue with local workflows or retry later with `iamu auth login`.\n"
|
|
13552
|
+
)
|
|
13530
13553
|
);
|
|
13531
13554
|
process.exitCode = 1;
|
|
13532
13555
|
return null;
|
|
@@ -16957,6 +16980,35 @@ function printStep(opts, record, projectRoot) {
|
|
|
16957
16980
|
}
|
|
16958
16981
|
}
|
|
16959
16982
|
async function browseStep(args, opts, driver) {
|
|
16983
|
+
if (opts.stepFile) {
|
|
16984
|
+
try {
|
|
16985
|
+
let raw;
|
|
16986
|
+
if (opts.stepFile === "-") {
|
|
16987
|
+
raw = readFileSync6(0, "utf8");
|
|
16988
|
+
} else {
|
|
16989
|
+
raw = readFileSync6(opts.stepFile, "utf8");
|
|
16990
|
+
}
|
|
16991
|
+
const data = JSON.parse(raw);
|
|
16992
|
+
if (data.run && typeof data.run === "string") opts.run = data.run;
|
|
16993
|
+
if (data.action && typeof data.action === "string")
|
|
16994
|
+
opts.action = data.action;
|
|
16995
|
+
if (data.note && typeof data.note === "string") opts.note = data.note;
|
|
16996
|
+
if (data.surface && typeof data.surface === "string")
|
|
16997
|
+
opts.surface = data.surface;
|
|
16998
|
+
if (args.length === 0 && data.cmd) {
|
|
16999
|
+
if (Array.isArray(data.cmd)) {
|
|
17000
|
+
args = data.cmd.map(String);
|
|
17001
|
+
} else if (typeof data.cmd === "string") {
|
|
17002
|
+
args = data.cmd.trim().split(/\s+/);
|
|
17003
|
+
}
|
|
17004
|
+
}
|
|
17005
|
+
} catch (err) {
|
|
17006
|
+
return fail(
|
|
17007
|
+
`Failed to read step payload from ${opts.stepFile}: ${err.message}`,
|
|
17008
|
+
opts
|
|
17009
|
+
);
|
|
17010
|
+
}
|
|
17011
|
+
}
|
|
16960
17012
|
if (!opts.run)
|
|
16961
17013
|
return fail("--run <run-id> is required for browse step.", opts);
|
|
16962
17014
|
if (!opts.action) {
|
|
@@ -18372,7 +18424,8 @@ function defaultFrontmatter(type2, id, slug, name, opts) {
|
|
|
18372
18424
|
...base,
|
|
18373
18425
|
name,
|
|
18374
18426
|
role: opts.role ?? "TODO",
|
|
18375
|
-
...opts.disposition ? { disposition: opts.disposition } : {}
|
|
18427
|
+
...opts.disposition ? { disposition: opts.disposition } : {},
|
|
18428
|
+
...opts.access ? { access: opts.access } : {}
|
|
18376
18429
|
};
|
|
18377
18430
|
case "outline":
|
|
18378
18431
|
return { ...base, title: name, ...description };
|
|
@@ -18441,7 +18494,7 @@ async function newEntity(type2, opts) {
|
|
|
18441
18494
|
}
|
|
18442
18495
|
const id = randomUUID9();
|
|
18443
18496
|
const frontmatter = defaultFrontmatter(entityType, id, slug, opts.name, opts);
|
|
18444
|
-
const body = "";
|
|
18497
|
+
const body = opts.body ?? opts.narrative ?? "";
|
|
18445
18498
|
try {
|
|
18446
18499
|
const record = await writeEntity(
|
|
18447
18500
|
projectRoot,
|
|
@@ -19412,8 +19465,21 @@ async function evaluate(runId, opts) {
|
|
|
19412
19465
|
)
|
|
19413
19466
|
};
|
|
19414
19467
|
const prompt = composeJudgePrompt(input);
|
|
19468
|
+
const promptFilePath = opts?.promptFile ?? path25.join(runDirPath, "judge_prompt.md");
|
|
19469
|
+
await fs25.writeFile(promptFilePath, prompt, "utf8");
|
|
19415
19470
|
if (opts?.json) {
|
|
19416
|
-
console.log(
|
|
19471
|
+
console.log(
|
|
19472
|
+
JSON.stringify(
|
|
19473
|
+
{
|
|
19474
|
+
...input,
|
|
19475
|
+
prompt_file: path25.relative(projectRoot, promptFilePath),
|
|
19476
|
+
prompt_file_abs: path25.resolve(promptFilePath),
|
|
19477
|
+
judge_prompt: prompt
|
|
19478
|
+
},
|
|
19479
|
+
null,
|
|
19480
|
+
2
|
|
19481
|
+
)
|
|
19482
|
+
);
|
|
19417
19483
|
return;
|
|
19418
19484
|
}
|
|
19419
19485
|
console.log(prompt);
|
|
@@ -19505,7 +19571,7 @@ ${formatIssues(fileResult.error)}`,
|
|
|
19505
19571
|
runId,
|
|
19506
19572
|
validatedVerdicts
|
|
19507
19573
|
);
|
|
19508
|
-
const cloudInfo = await pushRunToCloud(projectRoot, runId);
|
|
19574
|
+
const cloudInfo = opts?.push === false ? void 0 : await pushRunToCloud(projectRoot, runId);
|
|
19509
19575
|
if (opts?.json) {
|
|
19510
19576
|
console.log(
|
|
19511
19577
|
JSON.stringify(
|
|
@@ -19749,7 +19815,7 @@ async function collectCompletionExtras(run, opts) {
|
|
|
19749
19815
|
parseRunViewport(manifest.viewport)
|
|
19750
19816
|
);
|
|
19751
19817
|
const codeWarning = opts?.force ? null : codeChangedWarning(manifest.build, detectWorktreeState(projectRoot));
|
|
19752
|
-
const cloudInfo = await pushRunToCloud(projectRoot, runId);
|
|
19818
|
+
const cloudInfo = opts?.push === false ? void 0 : await pushRunToCloud(projectRoot, runId);
|
|
19753
19819
|
return { revisit, viewportWarning, codeWarning, cloudInfo };
|
|
19754
19820
|
}
|
|
19755
19821
|
function completeJsonPayload(canonical, extras) {
|
|
@@ -20202,9 +20268,28 @@ async function match(runId, opts) {
|
|
|
20202
20268
|
);
|
|
20203
20269
|
const needed = input.current.length > 0 && (input.prior.length > 0 || (input.guidance ?? []).length > 0);
|
|
20204
20270
|
const prompt = needed ? composeMatchPrompt(input) : null;
|
|
20271
|
+
const promptFilePath = opts?.promptFile ?? path27.join(runDirPath, "match_prompt.md");
|
|
20272
|
+
if (prompt) {
|
|
20273
|
+
await fs27.writeFile(promptFilePath, prompt, "utf8");
|
|
20274
|
+
} else {
|
|
20275
|
+
try {
|
|
20276
|
+
await fs27.unlink(promptFilePath);
|
|
20277
|
+
} catch {
|
|
20278
|
+
}
|
|
20279
|
+
}
|
|
20205
20280
|
if (opts?.json) {
|
|
20206
20281
|
console.log(
|
|
20207
|
-
JSON.stringify(
|
|
20282
|
+
JSON.stringify(
|
|
20283
|
+
{
|
|
20284
|
+
...input,
|
|
20285
|
+
needed,
|
|
20286
|
+
prompt_file: prompt ? path27.relative(ctx.projectRoot, promptFilePath) : null,
|
|
20287
|
+
prompt_file_abs: prompt ? path27.resolve(promptFilePath) : null,
|
|
20288
|
+
match_prompt: prompt
|
|
20289
|
+
},
|
|
20290
|
+
null,
|
|
20291
|
+
2
|
|
20292
|
+
)
|
|
20208
20293
|
);
|
|
20209
20294
|
return;
|
|
20210
20295
|
}
|
|
@@ -20435,7 +20520,7 @@ function registerCloudCommands(program) {
|
|
|
20435
20520
|
"Connect to local cloud stack (default port: 3000)"
|
|
20436
20521
|
).addOption(
|
|
20437
20522
|
new Option("-s, --staging", "Connect to staging cloud stack").hideHelp()
|
|
20438
|
-
).option("-t, --token <token>", "Authenticate directly with API token / key").option("--web-url <url>", "Custom web dashboard URL").option("--url <api-url>", "API URL (default: https://
|
|
20523
|
+
).option("-t, --token <token>", "Authenticate directly with API token / key").option("--web-url <url>", "Custom web dashboard URL").option("--url <api-url>", "API URL (default: https://app.iamu.dev)").option("-y, --yes", "Accept default project without interactive selection").option(
|
|
20439
20524
|
"--project <project-id>",
|
|
20440
20525
|
"Cloud project ID to link to, or `new` to create one. Required in a non-interactive shell when cloud projects exist"
|
|
20441
20526
|
).option("--no-browser", "Do not launch browser automatically").addHelpText(
|
|
@@ -20591,6 +20676,9 @@ function registerProjectCommands(program) {
|
|
|
20591
20676
|
program.command("new <type>").helpGroup("Project:").description(
|
|
20592
20677
|
"Create a new entity (persona, outline, capability, source, scenario)"
|
|
20593
20678
|
).requiredOption("--name <name>", "Entity name").option("--slug <slug>", "Custom entity slug (defaults to slugified name)").option("--role <role>", "Role description (persona only)").option("--disposition <text>", "Disposition / attitude (persona only)").option(
|
|
20679
|
+
"--access <role>",
|
|
20680
|
+
"Access role or testing account key (persona only)"
|
|
20681
|
+
).option("--body <text>", "Markdown body / narrative content").option("--narrative <text>", "Alias for --body").option(
|
|
20594
20682
|
"--description <text>",
|
|
20595
20683
|
"One-line description (capability, outline)"
|
|
20596
20684
|
).option("--outline <slug>", "Outline slug (scenario only)").option("--persona <slug>", "Persona slug (scenario only)").option(
|
|
@@ -20667,7 +20755,10 @@ function registerWalkthroughCommands(program) {
|
|
|
20667
20755
|
).option(
|
|
20668
20756
|
"--run <run-id>",
|
|
20669
20757
|
"Run ID to size browser (start) or record step into (step)"
|
|
20670
|
-
).option("--action <text>", "Action description (step only)").option("--note <text>", "Persona inner monologue / reasoning (step only)").option("--surface <name>", "Screen or surface name (step only)").option(
|
|
20758
|
+
).option("--action <text>", "Action description (step only)").option("--note <text>", "Persona inner monologue / reasoning (step only)").option("--surface <name>", "Screen or surface name (step only)").option(
|
|
20759
|
+
"--step-file <path>",
|
|
20760
|
+
"Read step payload (action, note, cmd) from a JSON file or '-' for stdin (step only)"
|
|
20761
|
+
).option("--width <px>", "Window width (start)").option("--height <px>", "Window height (start)").option("--headless", "Run without a window (start)").option(
|
|
20671
20762
|
"--port <port>",
|
|
20672
20763
|
"CDP port (start), default 9333",
|
|
20673
20764
|
(value) => parsePortOption(value)
|
|
@@ -20743,9 +20834,9 @@ function registerWalkthroughCommands(program) {
|
|
|
20743
20834
|
).option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--view", "Open results in browser immediately without prompt").option(
|
|
20744
20835
|
"--strict-provenance",
|
|
20745
20836
|
"Fail if steps show synthetic or programmatic timing anomalies"
|
|
20746
|
-
).addHelpText(
|
|
20837
|
+
).option("--no-push", "Skip pushing the run to Iamu Cloud").addHelpText(
|
|
20747
20838
|
"after",
|
|
20748
|
-
"\nExamples:\n $ iamu complete <run-id>\n $ iamu complete <run-id> --view\n $ iamu complete <run-id> --no-prompt\n $ iamu complete <run-id> --json\n $ iamu complete <run-id> --strict-provenance"
|
|
20839
|
+
"\nExamples:\n $ iamu complete <run-id>\n $ iamu complete <run-id> --view\n $ iamu complete <run-id> --no-prompt\n $ iamu complete <run-id> --no-push\n $ iamu complete <run-id> --json\n $ iamu complete <run-id> --strict-provenance"
|
|
20749
20840
|
).action(
|
|
20750
20841
|
async (runId, opts) => {
|
|
20751
20842
|
const { complete: complete2 } = await Promise.resolve().then(() => (init_complete(), complete_exports));
|
|
@@ -20754,23 +20845,27 @@ function registerWalkthroughCommands(program) {
|
|
|
20754
20845
|
);
|
|
20755
20846
|
program.command("match <run-id>").helpGroup("Walkthrough:").description(
|
|
20756
20847
|
"Compose the prompt that links this run's findings to earlier ones"
|
|
20757
|
-
).option("--json", "Output the match input bundle as JSON").
|
|
20758
|
-
|
|
20759
|
-
|
|
20760
|
-
|
|
20848
|
+
).option("--json", "Output the match input bundle as JSON").option("--prompt-file <path>", "Write the generated prompt to a file").action(
|
|
20849
|
+
async (runId, opts) => {
|
|
20850
|
+
const { match: match2 } = await Promise.resolve().then(() => (init_match(), match_exports));
|
|
20851
|
+
await match2(runId, opts);
|
|
20852
|
+
}
|
|
20853
|
+
);
|
|
20761
20854
|
program.command("match-record <run-id>").helpGroup("Walkthrough:").description(
|
|
20762
20855
|
"Record finding matches and re-derive the run's since-last-run delta"
|
|
20763
20856
|
).requiredOption("--file <path>", "Path to matches JSON file").option("--json", "Output match results as JSON").action(async (runId, opts) => {
|
|
20764
20857
|
const { matchRecord: matchRecord2 } = await Promise.resolve().then(() => (init_match(), match_exports));
|
|
20765
20858
|
await matchRecord2(runId, opts);
|
|
20766
20859
|
});
|
|
20767
|
-
program.command("evaluate <run-id>").helpGroup("Walkthrough:").description("Compose evaluation prompt for human-test questions").option("--json", "Output evaluation input bundle as JSON").
|
|
20768
|
-
|
|
20769
|
-
|
|
20770
|
-
|
|
20771
|
-
|
|
20860
|
+
program.command("evaluate <run-id>").helpGroup("Walkthrough:").description("Compose evaluation prompt for human-test questions").option("--json", "Output evaluation input bundle as JSON").option("--prompt-file <path>", "Write the generated prompt to a file").action(
|
|
20861
|
+
async (runId, opts) => {
|
|
20862
|
+
const { evaluate: evaluate2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
|
|
20863
|
+
await evaluate2(runId, opts);
|
|
20864
|
+
}
|
|
20865
|
+
);
|
|
20866
|
+
program.command("evaluate-record <run-id>").helpGroup("Walkthrough:").description("Record evaluation verdicts into the run's verdicts.json").requiredOption("--file <path>", "Path to verdicts JSON file").option("--json", "Output summary as JSON").option("-y, --yes", "Skip interactive prompts").option("--no-prompt", "Skip interactive prompt to view results").option("--no-push", "Skip pushing the updated run to Iamu Cloud").option("--view", "Open results in browser immediately without prompt").addHelpText(
|
|
20772
20867
|
"after",
|
|
20773
|
-
"\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
|
|
20868
|
+
"\nExamples:\n $ iamu evaluate-record <run-id> --file verdicts.json\n $ iamu evaluate-record <run-id> --file verdicts.json --no-prompt\n $ iamu evaluate-record <run-id> --file verdicts.json --no-push\n $ iamu evaluate-record <run-id> --file verdicts.json --json"
|
|
20774
20869
|
).action(
|
|
20775
20870
|
async (runId, opts) => {
|
|
20776
20871
|
const { evaluateRecord: evaluateRecord2 } = await Promise.resolve().then(() => (init_evaluate(), evaluate_exports));
|
|
@@ -67,47 +67,45 @@ Filter to `triage_status: open`.
|
|
|
67
67
|
|
|
68
68
|
A run that simply did not come across a finding proves nothing — never call a fix verified because it was not seen. After the list, if any fixes await a re-run, say how many and in which scenarios (`iamu status --json` → `rerun`, with `requests.open` for team requests), and offer `iamu-run <scenario>` for the first one.
|
|
69
69
|
|
|
70
|
-
Group by `scenario` field and render
|
|
70
|
+
Group by `scenario` field and render with an executive tally header, followed by a severity-sorted list per scenario group (CRITICAL → MAJOR → MINOR → OBS; hinders and missing first, helps last), including persona quotes, evidence, and clickable file links:
|
|
71
71
|
|
|
72
72
|
```
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
| # | Severity | Type | Finding | Slug |
|
|
87
|
-
|---|----------|-----------|--------------------------------------------------|------------------------------------------------------------|
|
|
88
|
-
| 5 | CRITICAL | incorrect | Cart total recalculates to wrong amount | dev-patel--checkout-abandon--cart-total-wrong-... |
|
|
89
|
-
| 6 | MAJOR | missing | No save-for-later affordance | dev-patel--checkout-abandon--no-save-for-later-... |
|
|
90
|
-
| 7 | MINOR | hinders | Auto-scroll on form error | dev-patel--checkout-abandon--auto-scroll-error-... |
|
|
73
|
+
Findings Tally: <N> Open (<C> Critical · <M> Major · <m> Minor) across <S> Scenarios
|
|
74
|
+
Awaiting verification: <K> addressed findings pending re-run
|
|
75
|
+
|
|
76
|
+
▼ [<scenario>](iamu/scenarios/<scenario>.md) (4 findings)
|
|
77
|
+
1. [CRITICAL · hinders] Handoff list is cluttered ([file](iamu/findings/<slug>.md))
|
|
78
|
+
• Persona: <Persona Name>: "<Persona reaction or consequence quote>"
|
|
79
|
+
• Evidence: Step <N> at <url>
|
|
80
|
+
• Recommendation: Add status filter chips
|
|
81
|
+
|
|
82
|
+
2. [MAJOR · missing] No visible confirmation after shift submit ([file](iamu/findings/<slug>.md))
|
|
83
|
+
• Persona: <Persona Name>: "<Persona reaction or consequence quote>"
|
|
84
|
+
• Evidence: Step <N> at <url>
|
|
85
|
+
• Recommendation: Show inline success toast
|
|
91
86
|
```
|
|
92
87
|
|
|
93
|
-
Ask the user
|
|
88
|
+
Ask the user how they would like to triage:
|
|
94
89
|
|
|
90
|
+
- **"walk through them"** → iterate through all open findings one-by-one in order with full context, code location, and triage choices (`[Fix now] [Skip / Dismiss] [Discuss] [Next]`).
|
|
95
91
|
- **"all critical"** → iterate through all critical findings in order.
|
|
96
92
|
- **Scenario group name** (e.g. "group 1") → iterate through that scenario's findings.
|
|
97
|
-
- **Single number or slug** → single finding.
|
|
93
|
+
- **Single number or slug** → single finding (skip to step 3).
|
|
94
|
+
- **"fix 1 and 2"** → make code fixes and mark addressed immediately.
|
|
95
|
+
- **"skip 3" / "dismiss 3"** → dismiss with reason (`out_of_scope`, `not_relevant`, `walker_error`, `duplicate`).
|
|
98
96
|
|
|
99
97
|
### 3. Direct triage: review one finding
|
|
100
98
|
|
|
101
|
-
Read the finding file at `iamu/findings/<slug>.md`. Parse the YAML frontmatter and markdown body. Render full detail:
|
|
99
|
+
Read the finding file at `iamu/findings/<slug>.md`. Parse the YAML frontmatter and markdown body. Render full detail with clickable links and evidence:
|
|
102
100
|
|
|
103
101
|
```
|
|
104
|
-
Finding: <title>
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
Type: <type> Severity: <severity> Triage: <triage_status>
|
|
102
|
+
Finding: <title> ([file](iamu/findings/<slug>.md))
|
|
103
|
+
Scenario: [<scenario>](iamu/scenarios/<scenario>.md)
|
|
104
|
+
Severity: <severity> · Type: <type> · Status: <triage_status>
|
|
108
105
|
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
Persona Quote: "<persona_reaction_or_consequence>"
|
|
107
|
+
UI Fact: <ui_fact>
|
|
108
|
+
Evidence: Step <N> at <url> (Screenshot: [view](iamu/.runs/<run>/screenshots/<NNN>.png))
|
|
111
109
|
|
|
112
110
|
Description:
|
|
113
111
|
<markdown body above ## Recommendation>
|
|
@@ -115,7 +113,7 @@ Description:
|
|
|
115
113
|
Recommendation:
|
|
116
114
|
<## Recommendation section, or "none">
|
|
117
115
|
|
|
118
|
-
|
|
116
|
+
Report: [report.md](iamu/.runs/<run>/report.md)
|
|
119
117
|
```
|
|
120
118
|
|
|
121
119
|
If the finding references a run directory, mention the report path for context. If the user wants to see the screenshot, read from `iamu/.runs/<run>/screenshots/`.
|
|
@@ -56,53 +56,48 @@ Determine the mode based on `$ARGUMENTS` and user intent:
|
|
|
56
56
|
|
|
57
57
|
### 2. Propose scenario seeds
|
|
58
58
|
|
|
59
|
-
Propose 2–3 scenario seeds
|
|
59
|
+
Propose 2–3 scenario seeds as scannable numbered cards. Do NOT use multi-column markdown tables with full prose sentences (they wrap awkwardly and break borders in terminal viewports). If personas exist in `iamu/personas/`, explicitly indicate which existing cast member pairs with each seed concept.
|
|
60
60
|
|
|
61
61
|
```
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
1. <Title> (<Type> · <existing persona slug or context actor>)
|
|
63
|
+
• Tension: <1 concise sentence on the human or organizational tension>
|
|
64
|
+
• Stress-tests: <What this reveals about the product>
|
|
65
|
+
|
|
66
|
+
2. <Title> (<Type> · <existing persona slug or context actor>)
|
|
67
|
+
• Tension: <1 concise sentence>
|
|
68
|
+
• Stress-tests: <What this reveals about the product>
|
|
69
|
+
|
|
70
|
+
3. <Title> (<Type> · <existing persona slug or context actor>)
|
|
71
|
+
• Tension: <1 concise sentence>
|
|
72
|
+
• Stress-tests: <What this reveals about the product>
|
|
67
73
|
```
|
|
68
74
|
|
|
69
75
|
Ask the user: "Which seed should we develop (1–3), or suggest another angle?"
|
|
70
76
|
|
|
71
77
|
### 3. Develop the situation
|
|
72
78
|
|
|
73
|
-
Once the user picks a direction, draft the
|
|
74
|
-
|
|
75
|
-
- **Narrative** (3–5 sentences) — mundane specifics, not abstract test language. Time pressure, competing priorities, real constraints. Write it as a human story.
|
|
76
|
-
- **Tension** (usually null; set only when two legitimate needs genuinely collide — e.g., speed vs. thoroughness, privacy vs. transparency)
|
|
77
|
-
- **Situation roles** (2–4 people with stakes) — each person should see the situation differently. Not conflict for drama — realistic tension like: one person wants to move on, another wants to investigate.
|
|
78
|
-
- **Complexity level**
|
|
79
|
-
|
|
80
|
-
**Before finalizing**, ask the user: "What should this walkthrough focus on?" This is the research question — what they want to learn. Examples: "Can a new admin onboard without training?", "Does the checkout flow work under time pressure?", "Is the reporting workflow accessible to non-technical users?"
|
|
81
|
-
|
|
82
|
-
From their answer, derive ONE concrete human test — a specific yes/partial/no checkpoint the evaluation step will score. Suggest it and let the user refine:
|
|
79
|
+
Once the user picks a direction (e.g. "1"), draft the situation concisely.
|
|
83
80
|
|
|
84
|
-
|
|
85
|
-
> Human test: "Could the admin complete employee bulk-import without consulting documentation?"
|
|
81
|
+
Do NOT ask an open-ended question like "What should this walkthrough focus on?" and then immediately answer it yourself in the same turn. Instead, propose an opinionated research focus question and one concrete binary (yes/partial/no) human checkpoint directly in the draft for the user to confirm or adjust.
|
|
86
82
|
|
|
87
|
-
|
|
83
|
+
Do NOT use markdown blockquote syntax (`>`), which renders as stray `|` pipe characters in terminal frontends. Keep the narrative capped at 2–3 punchy sentences (problem-space only, zero UI terms).
|
|
88
84
|
|
|
89
85
|
Present the draft to the user as a structured, scannable block **before creating anything**:
|
|
90
86
|
|
|
91
87
|
```
|
|
92
88
|
### Situation Draft: <Name>
|
|
93
89
|
|
|
94
|
-
|
|
95
|
-
>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
> **Human Checkpoint:** <derived checkpoint question>
|
|
90
|
+
Narrative: <2–3 sentences describing the human situation, time pressure, or physical reality without mentioning software UI>
|
|
91
|
+
Tension: <Legitimate colliding needs or "None">
|
|
92
|
+
Focus Question: <Proposed research focus question, e.g. "Can a frontline worker submit an urgent slip hazard report in under 60 seconds without abandoning floor duties?">
|
|
93
|
+
Human Checkpoint: <Concrete binary yes/partial/no question scored at evaluation>
|
|
99
94
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
95
|
+
Roles with Stakes:
|
|
96
|
+
• <Role 1>: <Stake>
|
|
97
|
+
• <Role 2>: <Stake>
|
|
103
98
|
```
|
|
104
99
|
|
|
105
|
-
|
|
100
|
+
Ask the user: "Ready to test this draft, or would you like to refine the focus question or circumstances? (Enter to accept, or type adjustments)"
|
|
106
101
|
|
|
107
102
|
### 4. Pick or propose personas
|
|
108
103
|
|
|
@@ -110,25 +105,25 @@ User approves, refines ("make it more time-pressured"), or rejects.
|
|
|
110
105
|
Inspect `iamu/personas/` (`iamu list personas`). If an existing persona in the casting panel is a natural fit for this situation, propose them first to build longitudinal test history:
|
|
111
106
|
`Reusable from panel: <slug> (<role>) — <why they fit this situation>`
|
|
112
107
|
|
|
113
|
-
If no existing persona fits, or if testing an uncovered perspective is needed, propose 2–3 persona candidates
|
|
114
|
-
|
|
115
|
-
- Different roles (the manager vs. the field worker vs. the auditor)
|
|
116
|
-
- Different dispositions (the patient learner vs. the harried pragmatist)
|
|
117
|
-
- Different contexts (first time vs. experienced, desktop vs. mobile, fluent vs. second-language)
|
|
108
|
+
If no existing persona fits, or if testing an uncovered perspective is needed, propose 2–3 persona candidates as numbered cards (do NOT use a wide table):
|
|
118
109
|
|
|
119
110
|
```
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
1. <Name> (<Role>)
|
|
112
|
+
• Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
|
|
113
|
+
• Why this tests something different: <Unique perspective or workflow divergence>
|
|
114
|
+
|
|
115
|
+
2. <Name> (<Role>)
|
|
116
|
+
• Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
|
|
117
|
+
• Why this tests something different: <Unique perspective or workflow divergence>
|
|
125
118
|
```
|
|
126
119
|
|
|
127
120
|
The user picks one (or more — each becomes a separate scenario). "New" to propose different candidates. "Skip" to save as draft without a persona.
|
|
128
121
|
|
|
129
122
|
### 5. Classify into capabilities
|
|
130
123
|
|
|
131
|
-
Situations carry ONE primary capability (product area grouping) and optional secondary capabilities (cross-cutting tags). Read existing capabilities from `iamu/capabilities
|
|
124
|
+
Situations carry ONE primary capability (product area grouping) and optional secondary capabilities (cross-cutting tags). Read existing capabilities directly from `iamu/capabilities/` or `iamu/context.yml`.
|
|
125
|
+
|
|
126
|
+
Do NOT execute interactive bash commands (like `iamu list capabilities`) during conversational turns; resolve capabilities silently from workspace files.
|
|
132
127
|
|
|
133
128
|
- **High confidence match** → assign silently, one line: `Capability: <slug> (auto)`
|
|
134
129
|
- **Low confidence or new** → ask: "Create new capability `<slug>`?"
|
|
@@ -178,12 +173,16 @@ For drafts (no persona): omit `--persona`, omit the brief body.
|
|
|
178
173
|
|
|
179
174
|
### 7. Summarize
|
|
180
175
|
|
|
176
|
+
Present the created entities with clickable file links and exact run commands:
|
|
177
|
+
|
|
181
178
|
```
|
|
182
|
-
Scenario: <scenario-slug>
|
|
183
|
-
Situation: <
|
|
184
|
-
Persona: <persona-
|
|
179
|
+
Created Scenario: [<scenario-slug>](iamu/scenarios/<scenario-slug>.md)
|
|
180
|
+
• Situation: [<outline-slug>](iamu/outlines/<outline-slug>.md)
|
|
181
|
+
• Persona: [<persona-slug>](iamu/personas/<persona-slug>.md) (or "draft — no persona bound yet")
|
|
182
|
+
• Capability: <primary_capability>
|
|
185
183
|
|
|
186
|
-
|
|
184
|
+
Next step:
|
|
185
|
+
iamu-run <scenario-slug> # Run walkthrough as <persona-name>
|
|
187
186
|
```
|
|
188
187
|
|
|
189
188
|
Run `iamu validate --all` to verify all entities before reporting done.
|
|
@@ -61,40 +61,56 @@ Four entry paths based on `$ARGUMENTS`:
|
|
|
61
61
|
- **Open-ended** (e.g. `iamu-propose`, `iamu-propose "what's missing?"`) — analyze coverage gaps across both scenarios and persona diversity. Prioritize uncovered capabilities and actors without personas.
|
|
62
62
|
- **Specific tension** (e.g. `iamu-propose "what happens when the safety coordinator disagrees with HR?"`) — use as seed but ground in context. Verify the tension is real (do these actors and dynamics exist in the domain?).
|
|
63
63
|
|
|
64
|
-
### 4. Present candidates (
|
|
64
|
+
### 4. Present candidates (Numbered Cards)
|
|
65
65
|
|
|
66
|
-
Present candidates
|
|
66
|
+
Present candidates as scannable numbered cards. Do NOT use multi-column markdown tables with full prose sentences (they wrap awkwardly and break borders in terminal viewports). Do NOT dump long paragraphs, full narratives, or regulatory citations upfront.
|
|
67
67
|
|
|
68
68
|
#### A. When proposing Scenarios:
|
|
69
69
|
|
|
70
|
-
Lead with
|
|
70
|
+
Lead with existing coverage using clickable links, then render the candidates:
|
|
71
71
|
|
|
72
72
|
```
|
|
73
|
-
Existing coverage: <N> scenarios (<
|
|
73
|
+
Existing coverage: <N> scenarios ([<slug1>](iamu/scenarios/<slug1>.md), ...). Uncovered areas: <gaps>.
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
| 2 | ... | ... | ... | ... |
|
|
79
|
-
| 3 | ... | ... | ... | ... |
|
|
75
|
+
1. <Short situation name> (<Actor from context>)
|
|
76
|
+
• Tension: <1-line human/domain tension>
|
|
77
|
+
• Stress-tests: <What this reveals about the product>
|
|
80
78
|
|
|
81
|
-
|
|
79
|
+
2. <Short situation name> (<Actor from context>)
|
|
80
|
+
• Tension: <1-line human/domain tension>
|
|
81
|
+
• Stress-tests: <What this reveals about the product>
|
|
82
|
+
|
|
83
|
+
3. <Short situation name> (<Actor from context>)
|
|
84
|
+
• Tension: <1-line human/domain tension>
|
|
85
|
+
• Stress-tests: <What this reveals about the product>
|
|
86
|
+
|
|
87
|
+
Next action:
|
|
88
|
+
Type 1, 2, or 3 to scaffold via iamu-new
|
|
89
|
+
Or describe adjustments (e.g. "make #2 more time-pressured", "explore <area>")
|
|
82
90
|
```
|
|
83
91
|
|
|
84
92
|
#### B. When proposing Personas:
|
|
85
93
|
|
|
86
|
-
Lead with existing persona coverage and uncovered roles from `context.yml`:
|
|
94
|
+
Lead with existing persona coverage using clickable links and uncovered roles from `context.yml`:
|
|
87
95
|
|
|
88
96
|
```
|
|
89
|
-
Existing personas: <
|
|
97
|
+
Existing personas: [<slug1>](iamu/personas/<slug1>.md), ... Uncovered roles from context.yml: <roles>.
|
|
98
|
+
|
|
99
|
+
1. <Name> (<Actor role>)
|
|
100
|
+
• Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
|
|
101
|
+
• Key Expectations & Vocabulary: <Domain terms and spec requirements>
|
|
102
|
+
|
|
103
|
+
2. <Name> (<Actor role>)
|
|
104
|
+
• Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
|
|
105
|
+
• Key Expectations & Vocabulary: <Domain terms and spec requirements>
|
|
90
106
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
| 2 | ... | ... | ... | ... |
|
|
95
|
-
| 3 | ... | ... | ... | ... |
|
|
107
|
+
3. <Name> (<Actor role>)
|
|
108
|
+
• Friction & Biases: <Specific friction triggers, skepticism, and bounce risks>
|
|
109
|
+
• Key Expectations & Vocabulary: <Domain terms and spec requirements>
|
|
96
110
|
|
|
97
|
-
|
|
111
|
+
Next action:
|
|
112
|
+
Type 1, 2, or 3 to scaffold via iamu-new
|
|
113
|
+
Or describe adjustments
|
|
98
114
|
```
|
|
99
115
|
|
|
100
116
|
Ground rules for generation:
|
|
@@ -215,6 +215,12 @@ Use atomic CLI commands to drive and record in one step — do NOT manually auth
|
|
|
215
215
|
iamu browse step --run <run-id> --action "Opened dashboard" --note "First thing I see is the overview panel" goto https://app.example.com/dashboard
|
|
216
216
|
iamu browse step --run <run-id> --action "Click checkout" --note "Button was hard to find" click button "Checkout"
|
|
217
217
|
```
|
|
218
|
+
**Avoid shell quoting friction:** When persona notes or actions contain quotes, apostrophes, or multi-line monologues, use `--step-file <path>` (or `-` for stdin) to avoid shell escaping errors:
|
|
219
|
+
```bash
|
|
220
|
+
iamu browse step --run <run-id> --step-file <path-to-step.json> click button "Checkout"
|
|
221
|
+
# or pass the entire action payload including cmd via JSON / stdin:
|
|
222
|
+
# { "action": "...", "note": "...", "cmd": ["click", "button", "Checkout"] }
|
|
223
|
+
```
|
|
218
224
|
This executes the browser action, waits for the DOM, takes the screenshot into `screenshots/step-N.png`, captures the URL, and writes `steps/NNN.json` atomically.
|
|
219
225
|
|
|
220
226
|
- **When using an external surface (iOS Simulator / custom MCP):**
|
|
@@ -249,26 +255,21 @@ Findings never name a human test: the walker does not see them. The judge links
|
|
|
249
255
|
|
|
250
256
|
After the walker returns, you MUST complete ALL of the following before presenting findings to the user. Do NOT present findings early. Do NOT ask the user anything. Execute steps A→B→C→D→E in order.
|
|
251
257
|
|
|
252
|
-
**A. Assemble canonical + report.** Use
|
|
258
|
+
**A. Assemble canonical + report (local).** Use `--no-push` so post-processing stays fast, local, and synchronous:
|
|
253
259
|
|
|
254
260
|
```bash
|
|
255
|
-
iamu complete <run-id> --no-prompt
|
|
261
|
+
iamu complete <run-id> --no-prompt --no-push --json
|
|
256
262
|
```
|
|
257
263
|
|
|
258
|
-
This reads all steps, findings, and entity files, assembles `canonical.json`, generates `report.md`, computes the delta against prior runs
|
|
264
|
+
This reads all steps, findings, and entity files, assembles `canonical.json`, generates `report.md`, and computes the delta against prior runs.
|
|
259
265
|
|
|
260
|
-
|
|
261
|
-
```bash
|
|
262
|
-
iamu complete <run-id> --no-prompt --json
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
**B. Match findings to earlier runs.** A fresh walker never words a recurring problem the same way twice, so `complete` alone reports recurrences as new and earlier findings as "not seen". Get the matcher bundle:
|
|
266
|
+
**B. Match findings to earlier runs.** Get the matcher bundle:
|
|
266
267
|
|
|
267
268
|
```bash
|
|
268
269
|
iamu match <run-id> --json
|
|
269
270
|
```
|
|
270
271
|
|
|
271
|
-
If `needed` is `false` (no earlier findings for this scenario, or none this run), skip to C. Otherwise
|
|
272
|
+
If `needed` is `false` (no earlier findings for this scenario, or none this run), skip to C. Otherwise, read the prompt from `iamu/.runs/<run-id>/match_prompt.md` directly and dispatch a matcher subagent with it as its only context. Write its JSON answer to `<matches.json>` and record it:
|
|
272
273
|
|
|
273
274
|
```bash
|
|
274
275
|
iamu match-record <run-id> --file <matches.json>
|
|
@@ -276,23 +277,23 @@ iamu match-record <run-id> --file <matches.json>
|
|
|
276
277
|
|
|
277
278
|
This links recurrences to their earlier canonical finding, marks earlier findings the run's steps show fixed (only with cited steps), and re-derives the delta and report. If the matcher's output is rejected, show the error to the matcher once and retry; if it fails again, continue without it — the exact-text delta from A stands.
|
|
278
279
|
|
|
279
|
-
**C. Evaluate human tests.**
|
|
280
|
+
**C. Evaluate human tests.** Get the evaluation prompt:
|
|
280
281
|
|
|
281
282
|
```bash
|
|
282
283
|
iamu evaluate <run-id> --json
|
|
283
284
|
```
|
|
284
285
|
|
|
285
|
-
|
|
286
|
+
Read the evaluation prompt from `iamu/.runs/<run-id>/judge_prompt.md` directly. Dispatch the evaluator as a subagent with that prompt. After the evaluator returns verdicts, record them locally with `--no-push`:
|
|
286
287
|
|
|
287
288
|
```bash
|
|
288
|
-
iamu evaluate-record <run-id> --file <verdicts.json> --no-prompt
|
|
289
|
+
iamu evaluate-record <run-id> --file <verdicts.json> --no-prompt --no-push
|
|
289
290
|
```
|
|
290
291
|
|
|
291
|
-
This
|
|
292
|
+
This links findings to human tests (`human_test_id`) and updates the report with judge verdicts.
|
|
292
293
|
|
|
293
294
|
**D. Read the completed canonical.** Read `iamu/.runs/<run-id>/canonical.json` for the final data including verification delta (if a prior run exists). Use this for step 5 presentation.
|
|
294
295
|
|
|
295
|
-
**E. Publish (linked mode only).**
|
|
296
|
+
**E. Publish (linked mode only).** Upload the completed run, screenshots, verdicts, and findings in one atomic sync:
|
|
296
297
|
|
|
297
298
|
```bash
|
|
298
299
|
iamu sync --json
|
|
@@ -320,15 +321,17 @@ The `walker_prompt` from `iamu instructions walk` is the source of truth and con
|
|
|
320
321
|
|
|
321
322
|
### 5. Present assessment — stay in the conversation
|
|
322
323
|
|
|
323
|
-
Render results **inline**
|
|
324
|
-
|
|
325
|
-
1. **Overall assessment** — answer the research question from the outline's human test. Read the outline's `human_tests[0].question` (the focus question the user defined when creating the scenario). Frame the verdict around it:
|
|
324
|
+
Render results **inline** with a high-contrast executive summary banner, followed by findings enriched with persona voice, evidence citations, and clickable file links.
|
|
326
325
|
|
|
327
|
-
|
|
326
|
+
1. **Executive Summary Banner & Focus Checkpoint**
|
|
328
327
|
|
|
329
|
-
|
|
328
|
+
Read the outline's `human_tests[0].question` and answer it directly. Use the evaluation verdict if available:
|
|
330
329
|
|
|
331
|
-
|
|
330
|
+
```
|
|
331
|
+
Walkthrough: [<scenario-slug>](iamu/scenarios/<scenario-slug>.md) ([<persona>](iamu/personas/<persona>.md))
|
|
332
|
+
Verdict: <FAIL / PARTIAL / PASS> · <N> Blockers (Critical) · <M> Friction points (Major/Minor) · <K> Helpers (Steps: <N>)
|
|
333
|
+
Focus Checkpoint: "<human_tests[0].question>" → <No / Partial / Yes>: <1-2 sentence direct answer explaining why>
|
|
334
|
+
```
|
|
332
335
|
|
|
333
336
|
2. **Progress since last run** (only when canonical.json contains a `verification` section). Present the delta:
|
|
334
337
|
|
|
@@ -340,25 +343,25 @@ Render results **inline** so the user can act without leaving the conversation.
|
|
|
340
343
|
+ 1 new since that run (date picker locale)
|
|
341
344
|
```
|
|
342
345
|
|
|
343
|
-
`resolved` means the matcher saw this run's steps do the thing the finding said failed — say which step. `not_observed` means only that this walk did not record the finding again. Never present it as fixed: the walker may have stopped before that screen or taken another route. Say which ones were not seen and, if the walk plainly never reached the screen they live on, say that too.
|
|
344
|
-
|
|
345
|
-
If no prior run exists, skip this.
|
|
346
|
+
`resolved` means the matcher saw this run's steps do the thing the finding said failed — say which step. `not_observed` means only that this walk did not record the finding again. Never present it as fixed: the walker may have stopped before that screen or taken another route. Say which ones were not seen and, if the walk plainly never reached the screen they live on, say that too.
|
|
346
347
|
|
|
347
|
-
3. **Findings** — severity-first (CRITICAL → MAJOR → MINOR), grouped by type (hinders and missing first
|
|
348
|
+
3. **Findings** — severity-first (CRITICAL → MAJOR → MINOR), grouped by type (hinders and missing first, helps at the bottom). For each finding, include the **persona reaction**, **evidence citation**, and **clickable link**:
|
|
348
349
|
|
|
349
350
|
**Hinders / Missing** (act on these):
|
|
350
351
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
352
|
+
1. [CRITICAL · hinders] Submit fails opaquely when required field empty ([file](iamu/findings/<slug>.md))
|
|
353
|
+
• Persona: <Persona Name>: "<Persona reaction quote or consequence showing real human friction>"
|
|
354
|
+
• Evidence: Step <N> at <url> (Screenshot: [view](iamu/.runs/<run-id>/screenshots/<NNN>.png))
|
|
355
|
+
• Recommendation: <Concrete recommendation from finding>
|
|
356
|
+
|
|
357
|
+
2. [MAJOR · hinders] Date picker has no "today" shortcut ([file](iamu/findings/<slug>.md))
|
|
358
|
+
• Persona: <Persona Name>: "<Persona reaction quote or consequence>"
|
|
359
|
+
• Evidence: Step <N> at <url>
|
|
360
|
+
• Recommendation: <Concrete recommendation from finding>
|
|
356
361
|
|
|
357
362
|
**Helps** (preserve these):
|
|
358
363
|
|
|
359
|
-
|
|
360
|
-
|---|------|---------|
|
|
361
|
-
| 4 | helps | Search auto-suggests from recent entries |
|
|
364
|
+
• [helps] Search auto-suggests from recent entries (Step <N>)
|
|
362
365
|
|
|
363
366
|
4. **What worked** — supportive moments worth preserving (brief, from `what_worked` in the canonical JSON).
|
|
364
367
|
|
|
@@ -369,16 +372,65 @@ Render results **inline** so the user can act without leaving the conversation.
|
|
|
369
372
|
|
|
370
373
|
6. **Cloud** — one line, by mode:
|
|
371
374
|
- **Linked, run on the cloud** → `Shareable report: <url>` (screenshots and step replay for anyone on the team).
|
|
372
|
-
- **Linked, run not on the cloud** → the reason from step E and its remedy, e.g. `Cloud: queued — retries on the next iamu sync
|
|
373
|
-
- **
|
|
374
|
-
- **Sync conflicts or pending deletions** (step E) → one line each: name the findings a teammate changed and give the CLI's resolution (`iamu pull --force` to take theirs after copying your edits aside, or `iamu sync --keep-mine` to keep yours — the user runs that one); for deletions, tell the user to review them and run `iamu sync --confirm-deletes` themselves.
|
|
375
|
-
- **Local-only** → nothing, with one exception: on the project's first completed run (`iamu status --json` → `runs.count` is 1), add `Want a link to share this report? iamu auth login connects the project to Iamu Cloud — optional, everything keeps working locally.` Never repeat it on later runs unless the user asks how to share a report.
|
|
375
|
+
- **Linked, run not on the cloud** → the reason from step E and its remedy, e.g. `Cloud: queued — retries on the next iamu sync`.
|
|
376
|
+
- **Local-only** → on first completed run: `Want a link to share this report? iamu auth login connects to Iamu Cloud — optional, everything keeps working locally.`
|
|
376
377
|
|
|
377
|
-
7. **
|
|
378
|
+
7. **Next actions (Conversational Triage)**:
|
|
378
379
|
|
|
379
|
-
|
|
380
|
+
Conclude your report with clear conversational prompts instead of raw terminal commands:
|
|
381
|
+
|
|
382
|
+
```
|
|
383
|
+
What would you like to do?
|
|
384
|
+
• "walk through them" → Review findings one by one with persona context & code location
|
|
385
|
+
• "fix 1 and 2" → Have me implement code fixes directly
|
|
386
|
+
• "discuss 2" → Ask why the persona hit this friction or explore trade-offs
|
|
387
|
+
• "skip 3" / "dismiss 3" → Dismiss finding (out of scope, intended, or walker error)
|
|
388
|
+
• "re-run" → Re-run walkthrough to verify fixes
|
|
389
|
+
```
|
|
380
390
|
|
|
381
|
-
|
|
391
|
+
### 6. Conversational Triage & Guided Review
|
|
392
|
+
|
|
393
|
+
The conversation is the triage surface. Do NOT eject the user to manual CLI commands or dump them at file paths.
|
|
394
|
+
|
|
395
|
+
#### A. Guided One-by-One Review ("walk through them" / "review one by one")
|
|
396
|
+
When the user asks to review findings one by one:
|
|
397
|
+
1. **Present Finding #N in isolation**:
|
|
398
|
+
- Number, severity, type, and title
|
|
399
|
+
- Persona consequence quote and why the friction occurred
|
|
400
|
+
- Relevant source code location (inspect project files to provide file path + line numbers)
|
|
401
|
+
- Step & screenshot evidence ([view](iamu/.runs/<run-id>/screenshots/<NNN>.png))
|
|
402
|
+
- Actionable recommendation
|
|
403
|
+
- Clear options prompt:
|
|
404
|
+
`Options: [Fix now] [Skip / Dismiss] [Discuss / Why] [Next finding]`
|
|
405
|
+
|
|
406
|
+
2. **Handle the user's decision**:
|
|
407
|
+
- **Fix now**:
|
|
408
|
+
Make the code edit, verify it loads (or check local tests/types), update the finding's frontmatter (`triage_status: addressed`, `triage_note: "<summary of fix>"`).
|
|
409
|
+
Tell the user the fix is applied and ask: "Ready for finding #<N+1>?".
|
|
410
|
+
- **Skip / Dismiss**:
|
|
411
|
+
If reason is not specified, ask or infer the appropriate category:
|
|
412
|
+
- `out_of_scope`: Not relevant to this project/flow scope.
|
|
413
|
+
- `not_relevant`: By design / intended behavior.
|
|
414
|
+
- `walker_error`: Walker misread the screen or made a navigational error.
|
|
415
|
+
- `duplicate`: Duplicate of another finding.
|
|
416
|
+
Execute: `iamu triage <slug> --status dismissed --reason <reason> --note "<why>"`.
|
|
417
|
+
Tell the user: "Dismissed as `<reason>` — created guidance rule in `iamu/guidance/<slug>.md` so future walkthroughs will not report this."
|
|
418
|
+
Then advance to finding #<N+1>.
|
|
419
|
+
- **Discuss / Why**:
|
|
420
|
+
Analyze why the persona experienced this friction, cite the persona brief and steps/screenshots, evaluate whether competitor tools solve this pattern, and give a direct opinion on whether it's worth fixing.
|
|
421
|
+
- **Next**:
|
|
422
|
+
Leave open (or set `triage_status: deferred` with note) and advance to finding #<N+1>.
|
|
423
|
+
|
|
424
|
+
3. **Wrap up after all findings are reviewed**:
|
|
425
|
+
- Run `iamu validate --all`.
|
|
426
|
+
- In linked mode, run `iamu sync --json` once so teammates see the triage decisions.
|
|
427
|
+
- Suggest re-running the walkthrough: `iamu-run <scenario-slug>` to verify fixes.
|
|
428
|
+
|
|
429
|
+
#### B. Direct Batch Actions ("fix 1 and 2", "fix all critical")
|
|
430
|
+
Read the finding details from the canonical JSON (already in context), inspect the code, make the edits, and update frontmatter to `triage_status: addressed` with `triage_note`.
|
|
431
|
+
|
|
432
|
+
#### C. Ad-hoc Questions & Challenges ("why did Karl do that?", "is #2 really a bug?")
|
|
433
|
+
Answer directly using persona brief context and step evidence. If the walker got confused or misinterpreted intended behavior, recommend dismissing as `walker_error` or `not_relevant` rather than adding unnecessary code.
|
|
382
434
|
|
|
383
435
|
**Linked mode: publish triage decisions.** When the user is done fixing and dismissing, run `iamu sync --json` once so teammates see the decisions (and any team request for these findings closes). Report it in one line (`Synced 3 findings to Iamu Cloud.`), with conflicts handled as in item 6. Do not sync after every single edit.
|
|
384
436
|
|
|
@@ -137,16 +137,17 @@ Persist the step-2 summary as structured fields so every scenario draft and walk
|
|
|
137
137
|
|
|
138
138
|
4. **Scaffold confirmed personas (unless `skip-personas` selected):**
|
|
139
139
|
|
|
140
|
-
|
|
140
|
+
Use the CLI to scaffold valid persona entities with schema-compliant UUIDs, slugs, frontmatter, and narrative body in a single command:
|
|
141
141
|
```bash
|
|
142
|
-
iamu new persona --name "<Name>" --role "<Role>" --disposition "<Disposition>" --json
|
|
142
|
+
iamu new persona --name "<Name>" --role "<Role>" --disposition "<Disposition>" --body "<2-4 sentence narrative detailing technical habits, patience level, and specific friction triggers>" [--access "<account-or-role>"] --json
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
If `iamu/context.yml` specifies an `access` mechanism, pass `--access "<role>"` matching an existing product account/role.
|
|
146
146
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
Once all confirmed personas are created, run validation once:
|
|
148
|
+
```bash
|
|
149
|
+
iamu validate --all
|
|
150
|
+
```
|
|
150
151
|
|
|
151
152
|
5. Confirm: "Context saved and personas seeded in iamu/personas/. Run `iamu-new` to draft your first scenario." (or "Context saved. Run `iamu-new` to draft your first scenario." if personas were skipped).
|
|
152
153
|
|
|
@@ -172,11 +173,15 @@ Three outcomes:
|
|
|
172
173
|
|
|
173
174
|
**Linking:**
|
|
174
175
|
|
|
175
|
-
1.
|
|
176
|
-
2. **Never pick the cloud project for the user.** In a non-interactive shell with existing cloud projects, login stops after sign-in and lists them as `iamu auth login --project <id>` lines plus `--project new`. Show that list, ask which project this repository belongs to, then re-run with their choice — the stored sign-in is reused, no second browser trip.
|
|
177
|
-
3. On success the output ends with `Dashboard: <url>` and, when an agent host was detected, `iamu-sync MCP server registered`. Relay both
|
|
176
|
+
1. Tell the user: "Opening browser for Iamu Cloud login..." then run `iamu auth login`. Allow the command at least 150 seconds for the user to complete sign-in in their browser. If your shell cannot wait that long, or runs where no browser can open (remote or container session), ask the user to run `iamu auth login` in their own terminal and tell you when it is done.
|
|
177
|
+
2. **Never pick the cloud project for the user.** In a non-interactive shell with existing cloud projects, login stops after sign-in and lists them as `iamu auth login --project <id>` lines plus `--project new`. Show that list, ask which project this repository belongs to, then re-run with their choice — the stored sign-in is reused, no second browser trip.
|
|
178
|
+
3. On success the output ends with `Dashboard: <url>` and, when an agent host was detected, `iamu-sync MCP server registered`. Relay both: the dashboard link, and that restarting the agent session loads the team tools (work requests, teammate-change alerts).
|
|
178
179
|
|
|
179
|
-
If login fails (cloud unreachable, sign-in timed out
|
|
180
|
+
If login times out or fails (cloud unreachable, sign-in timed out, or network error):
|
|
181
|
+
- Explain clearly what happened: "Cloud linking could not be completed (<echo specific reason from command output>)."
|
|
182
|
+
- Reassure the user: "Your local project setup is 100% complete and fully functional. Personas, scenarios, outlines, and walkthroughs run locally without cloud."
|
|
183
|
+
- Provide the next step for linking: "You can link to Iamu Cloud anytime later by running `iamu auth login` in your terminal."
|
|
184
|
+
- Point to the next creative action: "Next: run `iamu-new` to draft your first scenario."
|
|
180
185
|
|
|
181
186
|
All three outcomes leave a usable local setup. Cloud is strictly additive.
|
|
182
187
|
|
|
@@ -21,24 +21,28 @@ $ARGUMENTS
|
|
|
21
21
|
|
|
22
22
|
Do NOT use `find`, `grep`, or `cat` to dump raw `.md` files in `iamu/`. The CLI outputs clean, validated data.
|
|
23
23
|
|
|
24
|
-
### 2. Format entity responses
|
|
24
|
+
### 2. Format entity responses with an executive tally and clickable links
|
|
25
25
|
|
|
26
|
-
When the user asks for
|
|
26
|
+
When the user asks for project status, lead with an executive tally banner, followed by scannable tables with clickable markdown file links:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
Project Status: <P> Personas · <S> Scenarios (<R> Tested, <U> Untested) · <F> Open Findings · <C> Capabilities
|
|
30
|
+
```
|
|
27
31
|
|
|
28
32
|
**Personas:**
|
|
29
33
|
| Slug | Name | Role | Status |
|
|
30
34
|
|---|---|---|---|
|
|
31
|
-
| `elin-dahl` | Elin Dahl | Architect & first-time house owner in Falun | active |
|
|
35
|
+
| [`elin-dahl`](iamu/personas/elin-dahl.md) | Elin Dahl | Architect & first-time house owner in Falun | active |
|
|
32
36
|
|
|
33
37
|
**Scenarios:**
|
|
34
38
|
| Slug | Persona | Outline | Status / Target |
|
|
35
39
|
|---|---|---|---|
|
|
36
|
-
| `replacing-windows` | `elin-dahl` | `measure-and-order` | ready |
|
|
40
|
+
| [`replacing-windows`](iamu/scenarios/replacing-windows.md) | [`elin-dahl`](iamu/personas/elin-dahl.md) | [`measure-and-order`](iamu/outlines/measure-and-order.md) | ready |
|
|
37
41
|
|
|
38
42
|
**Findings:**
|
|
39
|
-
| # | Severity | Type | Finding |
|
|
43
|
+
| # | Severity | Type | Finding | File |
|
|
40
44
|
|---|---|---|---|---|
|
|
41
|
-
| 1 | CRITICAL | hinders | Submit fails opaquely on empty field |
|
|
45
|
+
| 1 | CRITICAL | hinders | Submit fails opaquely on empty field | [`view`](iamu/findings/<slug>.md) |
|
|
42
46
|
|
|
43
47
|
### 3. Ignore internal templates
|
|
44
48
|
|
|
@@ -52,13 +56,16 @@ For a project-status question, add one line on the cloud from `iamu status --jso
|
|
|
52
56
|
- **Linked, no credentials** → `Cloud: linked, but this machine has no credentials — iamu auth login.`
|
|
53
57
|
- **Local-only** → `Cloud: local-only.` Nothing more; no upgrade pitch.
|
|
54
58
|
|
|
55
|
-
### 5. Provide
|
|
59
|
+
### 5. Provide copy-pasteable next actions
|
|
60
|
+
|
|
61
|
+
Conclude with exact copy-pasteable commands:
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
|
|
63
|
+
```
|
|
64
|
+
Next actions:
|
|
65
|
+
iamu-run <scenario-slug> # Run a walkthrough for this scenario
|
|
66
|
+
iamu-propose # Propose missing personas or scenarios
|
|
67
|
+
iamu-new # Draft a new scenario or persona
|
|
68
|
+
iamu-findings # Triage open findings
|
|
69
|
+
iamu open # Open project in cloud dashboard
|
|
70
|
+
```
|
|
64
71
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iamu-dev/iamu",
|
|
3
|
-
"version": "0.2.0-beta.
|
|
3
|
+
"version": "0.2.0-beta.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Test your product as realistic personas — scenario-driven development CLI",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"typescript": "^5.8.0",
|
|
59
59
|
"vitest": "^4.1.11",
|
|
60
60
|
"@iamu-dev/local-store": "0.1.0",
|
|
61
|
-
"@iamu
|
|
62
|
-
"@iamu/
|
|
61
|
+
"@iamu/tsconfig": "0.1.0",
|
|
62
|
+
"@iamu-dev/protocol": "0.1.0"
|
|
63
63
|
},
|
|
64
64
|
"scripts": {
|
|
65
65
|
"build": "tsup && tsc -b tsconfig.build.json --emitDeclarationOnly && node scripts/copy-assets.mjs",
|