@aarwitz/tapp 0.17.0-rc.10 → 0.17.0-rc.12
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/.claude-plugin/marketplace.json +34 -0
- package/.claude-plugin/plugin.json +32 -0
- package/AGENTS.md +8 -3
- package/README.md +57 -7
- package/bin/tapp.js +32 -8
- package/docs/application-model.md +6 -4
- package/mcp-server/src/index.js +172 -81
- package/mcp-server/src/product-operations.js +26 -10
- package/mcp-server/src/web-explorer.js +120 -8
- package/package.json +4 -2
- package/skills/tapp/SKILL.md +74 -0
- package/skills/tapp/agents/openai.yaml +4 -0
- package/skills/tapp/references/commands.md +102 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tapp",
|
|
3
|
+
"description": "The official Tapp plugin: one agent skill and MCP tools for testing iOS, Android, and web apps on real surfaces.",
|
|
4
|
+
"owner": {
|
|
5
|
+
"name": "Aaron Horowitz",
|
|
6
|
+
"url": "https://github.com/aarwitz"
|
|
7
|
+
},
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "tapp",
|
|
11
|
+
"source": {
|
|
12
|
+
"source": "npm",
|
|
13
|
+
"package": "@aarwitz/tapp"
|
|
14
|
+
},
|
|
15
|
+
"description": "Test real iOS, Android, and web apps with Tapp. Includes the Tapp agent skill plus MCP hands, eyes, exploration, replayable Flows, and deterministic release evidence.",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "Aaron Horowitz",
|
|
18
|
+
"url": "https://github.com/aarwitz"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/aarwitz/tapp",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"keywords": [
|
|
23
|
+
"ios",
|
|
24
|
+
"simulator",
|
|
25
|
+
"testing",
|
|
26
|
+
"qa",
|
|
27
|
+
"xcuitest",
|
|
28
|
+
"mcp",
|
|
29
|
+
"agent-skill",
|
|
30
|
+
"copilot"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tapp",
|
|
3
|
+
"description": "Test real iOS, Android, and web apps with Tapp. Includes the Tapp agent skill plus MCP hands, eyes, exploration, replayable Flows, and deterministic release evidence.",
|
|
4
|
+
"version": "0.17.0-rc.12",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Aaron Horowitz",
|
|
7
|
+
"url": "https://github.com/aarwitz"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/aarwitz/tapp",
|
|
10
|
+
"repository": "https://github.com/aarwitz/tapp",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"ios",
|
|
14
|
+
"simulator",
|
|
15
|
+
"testing",
|
|
16
|
+
"qa",
|
|
17
|
+
"xcuitest",
|
|
18
|
+
"mcp",
|
|
19
|
+
"agent-skill",
|
|
20
|
+
"copilot"
|
|
21
|
+
],
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"tapp": {
|
|
24
|
+
"command": "node",
|
|
25
|
+
"args": [
|
|
26
|
+
"${CLAUDE_PLUGIN_ROOT}/bin/tapp.js",
|
|
27
|
+
"mcp"
|
|
28
|
+
],
|
|
29
|
+
"cwd": "${CLAUDE_PROJECT_DIR}"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
package/AGENTS.md
CHANGED
|
@@ -12,6 +12,7 @@ bundle id, or (web) an http(s) URL. You never need to know a bundle id up front.
|
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
14
|
npx -y @aarwitz/tapp explore [target] # autonomous exploration → findings + evidence (observation, not a gate; ≈ tapp_explore)
|
|
15
|
+
npx -y @aarwitz/tapp explore https://your-app.example --watch # web: visibly follow the same exploration
|
|
15
16
|
npx -y @aarwitz/tapp open [target] # launch + screen summary + screenshot saved to a file (≈ tapp_open_app)
|
|
16
17
|
npx -y @aarwitz/tapp tree [target] # accessibility tree, --json for every element (≈ tapp_ui_tree)
|
|
17
18
|
npx -y @aarwitz/tapp shot # screenshot the booted sim → file path (≈ tapp_screenshot)
|
|
@@ -22,8 +23,10 @@ npx -y @aarwitz/tapp flow run .tapp/flows/smoke.yml # committed, keyless E2E re
|
|
|
22
23
|
```
|
|
23
24
|
|
|
24
25
|
If repository onboarding detects multiple application targets, target detection is deterministic but
|
|
25
|
-
the choice is the user's.
|
|
26
|
-
|
|
26
|
+
the choice is the user's. Explicit `init --explore` asks even when the model has a saved default; a
|
|
27
|
+
later bare `explore` may consume that default. In a human TTY, Tapp displays a numbered selector and
|
|
28
|
+
continues in the same command. A non-interactive CLI prints the exact choices and exits before
|
|
29
|
+
building. MCP returns
|
|
27
30
|
`reason: "target-selection-required"` with structured `choices[]` (`platform`, `name`, `sourcePath`,
|
|
28
31
|
`selector`, and exact `command`). **Do not pick one yourself.** Present those choices to the user
|
|
29
32
|
with the client's native multiple-choice question UI when available, then rerun using the selected
|
|
@@ -41,7 +44,9 @@ that IS the screen. If you cannot (Cursor, VS Code Copilot), connect the MCP ser
|
|
|
41
44
|
instead: its tool results carry the screenshot inline. Screen *recordings* are for the
|
|
42
45
|
human: on **iOS**, `tapp explore` records the full exploration and embeds it in the report.html
|
|
43
46
|
evidence page (Android does not currently record video) — tell the user the report path so they can
|
|
44
|
-
watch it.
|
|
47
|
+
watch it. On **web**, explicit `--watch` opens the isolated Playwright Chromium window and overlays
|
|
48
|
+
Tapp's current action and pointer; the overlay is omitted from evidence screenshots. It does not
|
|
49
|
+
drive the person's existing/default browser profile.
|
|
45
50
|
|
|
46
51
|
The interactive session/record loop is MCP-only (it needs a long-lived process). Flow replay is
|
|
47
52
|
also available in the CLI. The rest of this playbook assumes the `tapp_*` MCP tools are connected. With
|
package/README.md
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@aarwitz/tapp)
|
|
5
5
|
[](https://www.npmjs.com/package/@aarwitz/tapp)
|
|
6
6
|
[](./LICENSE)
|
|
7
|
+
[](https://skills.sh/aarwitz/tapp)
|
|
8
|
+
[](https://marketplace.visualstudio.com/items?itemName=lidi-solutions.tapp)
|
|
7
9
|
[](cursor://anysphere.cursor-deeplink/mcp/install?name=tapp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBhYXJ3aXR6L3RhcHAiLCJtY3AiXX0=)
|
|
8
|
-
[](https://insiders.vscode.dev/redirect/mcp/install?name=tapp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40aarwitz%2Ftapp%22%2C%22mcp%22%5D%7D)
|
|
9
11
|
|
|
10
12
|
**Tapp is the release-contract and evidence layer for teams shipping agent-authored applications.**
|
|
11
13
|
It turns a repository and real product into an observed UI Map, a compact reviewed deterministic
|
|
@@ -31,6 +33,47 @@ Three platforms, one observe-and-gate engine:
|
|
|
31
33
|
autonomous exploration, the deterministic detectors (uncaught exceptions, failed requests,
|
|
32
34
|
dead buttons, broken links, placeholder `href="#"` links, error pages), and the same gate.
|
|
33
35
|
|
|
36
|
+
## Give Tapp to your coding agent
|
|
37
|
+
|
|
38
|
+
After setup, the whole user prompt is:
|
|
39
|
+
|
|
40
|
+
> Use Tapp to test this app.
|
|
41
|
+
|
|
42
|
+
The official skill teaches the agent to choose the smallest useful operation, handle repositories
|
|
43
|
+
with multiple app targets, inspect visual evidence, and keep exploration observations separate from
|
|
44
|
+
release judgment.
|
|
45
|
+
|
|
46
|
+
**Claude Code — skill and MCP tools together:**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
claude plugin marketplace add aarwitz/tapp
|
|
50
|
+
claude plugin install tapp@tapp
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Restart Claude Code after installation, open the application repository, and use the short prompt
|
|
54
|
+
above. The plugin bundles both the `tapp` Agent Skill and the local stdio MCP server; no additional
|
|
55
|
+
prompt block or bundle id is required.
|
|
56
|
+
|
|
57
|
+
**Claude, Codex, Cursor, Copilot, and other Agent Skills clients — skill only:**
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx -y skills add aarwitz/tapp --skill tapp
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
This installs the open Agent Skills version of the same instructions into the current project and
|
|
64
|
+
lets the agent fall back to the npm CLI when MCP is not connected. Add `-g` for a user-wide install,
|
|
65
|
+
or `--agent claude-code`, `--agent codex`, and similar selectors to constrain the clients.
|
|
66
|
+
|
|
67
|
+
**No agent integration:** run the npm package directly from an app repository:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx -y @aarwitz/tapp init . --explore
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**VS Code:** install [Tapp from the Marketplace](https://marketplace.visualstudio.com/items?itemName=lidi-solutions.tapp).
|
|
74
|
+
It contributes the same cross-platform Agent Skill to Copilot plus focused iOS simulator tools and a
|
|
75
|
+
live simulator panel. Android and web remain available through the skill's CLI/MCP workflow.
|
|
76
|
+
|
|
34
77
|
```
|
|
35
78
|
you: "Add a logout button to the settings screen"
|
|
36
79
|
agent: *writes the Swift*
|
|
@@ -38,7 +81,7 @@ agent: *tapp: builds, opens the app, navigates to Settings, screenshots it*
|
|
|
38
81
|
agent: "Done — and here it is working on the simulator: [screenshot]"
|
|
39
82
|
```
|
|
40
83
|
|
|
41
|
-
##
|
|
84
|
+
## npm CLI quickstart
|
|
42
85
|
|
|
43
86
|
Requirements: **Node ≥ 18**. iOS needs **macOS + Xcode**; Android needs `adb` plus a connected
|
|
44
87
|
emulator/device; web needs Playwright + Chromium.
|
|
@@ -80,11 +123,14 @@ npx -y @aarwitz/tapp baseline create . --platform web
|
|
|
80
123
|
npx -y @aarwitz/tapp ci install .
|
|
81
124
|
```
|
|
82
125
|
|
|
83
|
-
|
|
84
|
-
`tapp init . --explore` does not guess from detection order
|
|
126
|
+
In a repository containing multiple apps (for example, iOS plus web),
|
|
127
|
+
`tapp init . --explore` without an explicit target does not guess from detection order—even when a
|
|
128
|
+
prior choice is recorded. A human terminal gets a numbered
|
|
85
129
|
selector; a non-interactive CLI prints exact target-selection commands, while MCP also returns
|
|
86
130
|
structured choices. Neither builds or writes before the choice. After you choose one, the model
|
|
87
|
-
retains every detected target and records the choice as the default for the next bare `tapp explore
|
|
131
|
+
retains every detected target and records the choice as the default for the next bare `tapp explore`;
|
|
132
|
+
explicit `init --explore` continues to ask because it is the onboarding/refresh operation. Setup gaps
|
|
133
|
+
belonging only to unselected targets are shown as informational, not as failures of the selected run.
|
|
88
134
|
|
|
89
135
|
The baseline command writes only after exploration and every selected deterministic suite pass
|
|
90
136
|
conclusively. It stores `.tapp/baselines/<platform>/<target-id>.json`; the generated workflow
|
|
@@ -106,7 +152,9 @@ npx -y @aarwitz/tapp build [dir] # just build + install (scheme auto-detecte
|
|
|
106
152
|
```
|
|
107
153
|
|
|
108
154
|
Web (beta): `npx -y @aarwitz/tapp explore http://localhost:3000` *(one-time setup:
|
|
109
|
-
`npm i -g playwright && npx playwright install chromium`)
|
|
155
|
+
`npm i -g playwright && npx playwright install chromium`)*. Add `--watch` to open Tapp's controlled,
|
|
156
|
+
isolated Chromium window and follow its clicks with an on-page pointer/action label. Tapp hides that
|
|
157
|
+
watch UI from saved evidence screenshots and does not automate your personal/default browser profile.
|
|
110
158
|
|
|
111
159
|
Focused web inspection waits briefly for loading states to settle. If a consent or location modal
|
|
112
160
|
blocks the screen, dismiss it and wait for the content you care about in the same package-only call:
|
|
@@ -191,7 +239,9 @@ Then ask your agent:
|
|
|
191
239
|
| 📱 | `tapp_list_simulators` / `boot_simulator` / `install_app` | Simulator + app management. |
|
|
192
240
|
| 🩺 | `tapp_health`, `tapp_capture*`, `tapp_parse_markers` | Diagnostics and capture history. |
|
|
193
241
|
|
|
194
|
-
|
|
242
|
+
Canonical installable skill: [`skills/tapp/SKILL.md`](skills/tapp/SKILL.md). Full low-level tool
|
|
243
|
+
reference: [AGENTS.md](./AGENTS.md). Both ship inside the npm package; installing the Claude plugin
|
|
244
|
+
or Agent Skill is what makes the workflow discoverable without pasting instructions.
|
|
195
245
|
Application-model and import contract: [`docs/application-model.md`](docs/application-model.md).
|
|
196
246
|
The desktop Coverage view reads the same `.tapp/application-model.json`,
|
|
197
247
|
`.tapp/release-plan.json`, and `.tapp/ui-map.json`, including explicit proposal review; it
|
package/bin/tapp.js
CHANGED
|
@@ -240,8 +240,8 @@ async function resolveTargetOrExit(engine, input) {
|
|
|
240
240
|
|
|
241
241
|
function safeCommandUsage(verb) {
|
|
242
242
|
const usage = {
|
|
243
|
-
explore: "tapp explore [target] [--platform ios|android|web] [--actions N] [--timeout SEC] [--email VALUE] [--password VALUE] [--baseline FILE] [--json FILE]\n iOS launch configuration: [--launch-arg VALUE ...] [--launch-env '{\"KEY\":\"VALUE\"}']\n Android: [--app-id ID] [--apk FILE] [--serial ID] [--keep-data]",
|
|
244
|
-
init: "tapp init [repo] [--explore] [--refresh] [--platform PLATFORM] [--target NAME] [--url URL] [--dry-run]",
|
|
243
|
+
explore: "tapp explore [target] [--platform ios|android|web] [--actions N] [--timeout SEC] [--email VALUE] [--password VALUE] [--baseline FILE] [--json FILE]\n Web: [--watch] opens Tapp's controlled browser and shows its actions\n iOS launch configuration: [--launch-arg VALUE ...] [--launch-env '{\"KEY\":\"VALUE\"}']\n Android: [--app-id ID] [--apk FILE] [--serial ID] [--keep-data]",
|
|
244
|
+
init: "tapp init [repo] [--explore] [--refresh] [--platform PLATFORM] [--target NAME] [--url URL] [--watch] [--dry-run]",
|
|
245
245
|
open: "tapp open [target] [--platform ios|android|web] [--out FILE] [--tap TEXT] [--wait-for TEXT]",
|
|
246
246
|
tree: "tapp tree [target] [--platform ios|android|web] [--json] [--tap TEXT] [--wait-for TEXT]",
|
|
247
247
|
shot: "tapp shot [--out FILE]",
|
|
@@ -346,6 +346,7 @@ switch (command) {
|
|
|
346
346
|
timeout,
|
|
347
347
|
testEmail: typeof flags.email === "string" ? flags.email : undefined,
|
|
348
348
|
testPassword: typeof flags.password === "string" ? flags.password : undefined,
|
|
349
|
+
watch: flags.watch === true,
|
|
349
350
|
runExploration: engine?.runInitExploration,
|
|
350
351
|
onProgress: (progress) => {
|
|
351
352
|
const activePlatform = progress.platform || platform;
|
|
@@ -387,17 +388,29 @@ switch (command) {
|
|
|
387
388
|
if (typeof flags["json-out"] === "string") {
|
|
388
389
|
const out = path.resolve(flags["json-out"]);
|
|
389
390
|
fs.mkdirSync(path.dirname(out), { recursive: true });
|
|
390
|
-
fs.writeFileSync(out, JSON.stringify({
|
|
391
|
-
|
|
392
|
-
|
|
391
|
+
fs.writeFileSync(out, JSON.stringify({
|
|
392
|
+
model: built.model,
|
|
393
|
+
plan: written?.plan || built.plan,
|
|
394
|
+
...(exploration ? { exploration } : {}),
|
|
395
|
+
...(result.selectedTarget ? { selectedTarget: result.selectedTarget } : {}),
|
|
396
|
+
requirementScope: result.requirementScope,
|
|
397
|
+
}, null, 2) + "\n");
|
|
398
|
+
}
|
|
399
|
+
const activeRequirements = result.requirementScope?.active || built.model.requirements;
|
|
400
|
+
const deferredRequirements = result.requirementScope?.deferred || [];
|
|
401
|
+
const blocking = activeRequirements.filter((item) => item.severity === "blocking");
|
|
402
|
+
const deferredBlocking = deferredRequirements.filter((item) => item.severity === "blocking");
|
|
393
403
|
const pending = (written?.plan || built.plan).items.filter((item) => item.decision === "pending");
|
|
394
404
|
console.log(`🧭 Tapp init — ${built.model.application.name}`);
|
|
395
405
|
console.log(` targets: ${built.model.targets.length ? built.model.targets.map((target) => `${target.platform}:${target.name}`).join(", ") : "none"}`);
|
|
396
406
|
console.log(` UI Map: ${built.model.uiMap.status} · ${built.model.uiMap.nodeCount} states · ${built.model.uiMap.edgeCount} transitions`);
|
|
397
407
|
if (exploration) console.log(` Exploration: ${(exploration.findings || []).length} finding(s)${exploration.inconclusive ? " (inconclusive)" : ""} · ${exploration.uiMap.nodeCount} states · evidence: ${exploration.reportHtml || exploration.capture?.path || "capture recorded"}`);
|
|
398
408
|
if (exploration?.managedRuntime) console.log(` Managed web runtime: built/started ${exploration.target} for exploration and stopped it afterward · log: ${exploration.runtime.logPath}`);
|
|
399
|
-
|
|
400
|
-
|
|
409
|
+
const selectedLabel = result.selectedTarget ? ` for ${result.selectedTarget.platform}:${result.selectedTarget.name}` : "";
|
|
410
|
+
const deferredLabel = deferredBlocking.length ? ` · ${deferredBlocking.length} setup gap(s) on unselected target(s)` : "";
|
|
411
|
+
console.log(` release plan: ${(written?.plan || built.plan).items.length} item(s) · ${pending.length} pending review · ${blocking.length} blocking requirement(s)${selectedLabel}${deferredLabel}`);
|
|
412
|
+
for (const requirement of activeRequirements) console.log(` ${requirement.severity === "blocking" ? "❌" : "⚠️"} ${requirement.message} Next: ${requirement.remediation}`);
|
|
413
|
+
for (const requirement of deferredRequirements) console.log(` ℹ️ Unselected ${requirement.targetPlatform}:${requirement.targetName} setup gap: ${requirement.message} Next: ${requirement.remediation}`);
|
|
401
414
|
if (written) console.log(` model: ${written.modelPath}\n plan: ${written.planPath}`);
|
|
402
415
|
else console.log(" dry run: repository files were not changed");
|
|
403
416
|
break;
|
|
@@ -545,6 +558,7 @@ switch (command) {
|
|
|
545
558
|
testPassword: flags.password,
|
|
546
559
|
...launchOptions,
|
|
547
560
|
baselineFindings,
|
|
561
|
+
watch: flags.watch === true,
|
|
548
562
|
surface: "cli",
|
|
549
563
|
onProgress,
|
|
550
564
|
onStatus: (t) => console.error(`ℹ️ ${t}`),
|
|
@@ -565,6 +579,10 @@ switch (command) {
|
|
|
565
579
|
process.exit(2);
|
|
566
580
|
}
|
|
567
581
|
if (platform === "ios") requireMacFor("iOS testing");
|
|
582
|
+
if (flags.watch === true && platform !== "web") {
|
|
583
|
+
console.error("❌ --watch is currently available for web exploration only");
|
|
584
|
+
process.exit(2);
|
|
585
|
+
}
|
|
568
586
|
if (platform !== "ios" && Object.keys(launchOptions).length) {
|
|
569
587
|
console.error("❌ --launch-arg and --launch-env apply only to iOS targets");
|
|
570
588
|
process.exit(2);
|
|
@@ -586,6 +604,7 @@ switch (command) {
|
|
|
586
604
|
testEmail: flags.email,
|
|
587
605
|
testPassword: flags.password,
|
|
588
606
|
baselineFindings,
|
|
607
|
+
watch: flags.watch === true,
|
|
589
608
|
surface: "cli",
|
|
590
609
|
onProgress,
|
|
591
610
|
})
|
|
@@ -1557,7 +1576,7 @@ switch (command) {
|
|
|
1557
1576
|
Core — explore, prove, gate (agents and humans can just run these — no server, no setup):
|
|
1558
1577
|
tapp explore [target] Autonomous exploration → findings + evidence (an observation, NOT a
|
|
1559
1578
|
release decision — run 'tapp ci' to gate a merge)
|
|
1560
|
-
(--platform ios|android|web · --
|
|
1579
|
+
(web: --watch · all: --platform ios|android|web · --actions N)
|
|
1561
1580
|
tapp contract run FILE Replay a business-level release contract — the guarantees that must hold
|
|
1562
1581
|
tapp ci ... Merge-blocking release gate — explore + suites + baseline → pass/fail/inconclusive
|
|
1563
1582
|
(see: tapp ci --help)
|
|
@@ -1617,6 +1636,11 @@ Setup:
|
|
|
1617
1636
|
tapp doctor Check Xcode / simulators / toolchain
|
|
1618
1637
|
tapp mcp Start the MCP server on stdio (adds inline screenshots + interactive sessions)
|
|
1619
1638
|
|
|
1639
|
+
Agent Skill (optional — so a short “Use Tapp to test this app” prompt is enough):
|
|
1640
|
+
Any supported agent: npx -y skills add aarwitz/tapp --skill tapp
|
|
1641
|
+
Claude skill + MCP: claude plugin marketplace add aarwitz/tapp
|
|
1642
|
+
claude plugin install tapp@tapp
|
|
1643
|
+
|
|
1620
1644
|
MCP hookup (optional — for inline screenshots and the tap/type/inspect session loop):
|
|
1621
1645
|
Claude Code: claude mcp add tapp -- npx -y @aarwitz/tapp mcp
|
|
1622
1646
|
Cursor/VS Code (mcp.json):
|
|
@@ -16,12 +16,14 @@ resolution actually builds and installs the detected Xcode container, the model
|
|
|
16
16
|
scheme as runtime-observed validation and removes the corresponding confirmation blocker. Merely
|
|
17
17
|
supplying a bundle id or prebuilt `.app` does not prove repository build configuration.
|
|
18
18
|
|
|
19
|
-
A
|
|
20
|
-
|
|
19
|
+
A repository with more than one detected application target is never resolved by detection order
|
|
20
|
+
during explicit initialization, even when a prior default exists. Bare `tapp init . --explore`
|
|
21
|
+
prompts in a human TTY; non-interactive CLI/MCP callers receive
|
|
21
22
|
exact `--platform`/`--target` commands before any build or write, and MCP also carries them as
|
|
22
23
|
structured `target-selection-required` choices. The selected run records that target as the default
|
|
23
|
-
for later bare
|
|
24
|
-
and their unmet coverage.
|
|
24
|
+
for later bare `tapp explore`, but the application model retains the repository's other detected
|
|
25
|
+
targets and their unmet coverage. The selected init run reports other-target setup gaps as deferred
|
|
26
|
+
information rather than presenting them as failures of the target that was actually explored.
|
|
25
27
|
|
|
26
28
|
## First inspection
|
|
27
29
|
|