@appliqation/explorer 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/cli/audit.js +25 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/index.js +122 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/output.js +20 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/config/env.js +52 -0
- package/dist/config/env.js.map +1 -0
- package/dist/orchestrator/explore.js +67 -0
- package/dist/orchestrator/explore.js.map +1 -0
- package/dist/tools/safety.js +24 -0
- package/dist/tools/safety.js.map +1 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Appliqation Pty Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Appliqation Explorer
|
|
2
|
+
|
|
3
|
+
**Runs Appliqation's exploratory-QA workflow (`appq:runman`) headlessly against a live app under test — the same senior-QA heuristics pass a human runs interactively in Claude Code, without a human at the confirmation gate.**
|
|
4
|
+
|
|
5
|
+
Point it at a URL (or let it resolve one from a project) and a plain-English intent, and it drives a real Playwright browser through surface mapping, a 13-category senior-QA heuristics pass, and mandatory security/network/caching/mobile probes — the exact same methodology Appliqation already serves interactively, just run unattended.
|
|
6
|
+
|
|
7
|
+
## Why this exists
|
|
8
|
+
|
|
9
|
+
Every other agent in this family answers a narrow, structured question: does this test case pass (autotest), is there a script for it (scriptgen), can this defect be fixed (defect-fix). None of them go looking for the bugs a scripted test never checks for — accessibility gaps, race conditions, caching bugs, things that only show up when someone actually explores. Appliqation already has this covered as `appq:runman`, but until now the only way to run it was interactively. This is the standalone, unattended client for it.
|
|
10
|
+
|
|
11
|
+
## The one thing this agent deliberately can't do
|
|
12
|
+
|
|
13
|
+
`appq:runman`'s own prompt ends a pass by calling `enrich_project_context` with `action=write`, to persist findings (`known_issues`, `high_risk_areas`, `regression_watchlist`) as memory for future passes. **This agent refuses that call.**
|
|
14
|
+
|
|
15
|
+
When `appq:runman` runs interactively inside Claude Code, a human is present at its Phase 2 confirmation gate and reads the findings report before anything happens next — informal but real supervision over what gets written back as fact for future agents to trust. A standalone, headless invocation has no equivalent: nothing reviews it turn to turn. So this agent holds the conservative default instead: it can read project context (`enrich_project_context` with `action=read` — informs what's worth exploring), but a write attempt is refused at the dispatch layer, in code, before it ever reaches appq — not honored just because the served prompt asks for it. Genuinely read-only end to end; see [`@appliqation/agent-core`](https://github.com/appliqation/appliqation-agent-core)'s `createReadOnlyProjectContextDispatcher`.
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g @appliqation/explorer
|
|
21
|
+
npx playwright install chromium
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Create a `.env` file (in whatever directory you'll run it from) with:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
APPQ_API_KEY=your-appliqation-api-key # read-only is enough
|
|
28
|
+
ANTHROPIC_API_KEY=your-anthropic-key # or OPENAI_API_KEY — pick one
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
appliqation-explorer explore \
|
|
33
|
+
--prompt "Explore the signup flow like a senior QA lead, focus on the phone number field" \
|
|
34
|
+
--project-id 1349 \
|
|
35
|
+
--site-url https://stage.example.com
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Add `--json`/`--ci` for a structured summary. There's no `--dry-run` — this agent never has real write access to anything, so there's nothing to suppress. The exit code is 0 unless the pass hit its own budget cap and ended early; "found bugs" is never a failure — that's the entire point of running it.
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
Copy `.env.example` to `.env`. Requires `APPQ_API_KEY` (read-only access is sufficient) and one of `ANTHROPIC_API_KEY`/`OPENAI_API_KEY`. `EXPLORE_MAX_STEPS`/`EXPLORE_MAX_PAGES`/`EXPLORE_MAX_MINUTES` are the workflow's own self-regulated budget (what the model is told to respect); `BUDGET_MAX_*` is a separate, code-enforced backstop set generously above them in case the model doesn't honor its own limits.
|
|
43
|
+
|
|
44
|
+
## Development
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/appliqation/appliqation-explorer.git
|
|
48
|
+
cd appliqation-explorer
|
|
49
|
+
npm install
|
|
50
|
+
cp .env.example .env # fill in APPQ_API_KEY (read-only is enough) and one LLM provider key
|
|
51
|
+
npm run dev -- explore --prompt "<text>" [--project-id <id>] [--site-url <url>]
|
|
52
|
+
npm run typecheck
|
|
53
|
+
npm test
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
See `CLAUDE.md` for a map of this repo if you're working in it with an AI coding assistant.
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Extracted out of cli/index.ts so this is testable without triggering that
|
|
2
|
+
// file's top-level program.parseAsync(process.argv) side effect — same
|
|
3
|
+
// reasoning as appliqation-autotest's cli/resolvers.ts.
|
|
4
|
+
import { safeRecord } from '@appliqation/agent-core';
|
|
5
|
+
export async function recordExploreRun(args) {
|
|
6
|
+
const { sink, startedAt, endedAt, model, usage, prompt, projectId, siteUrl, result } = args;
|
|
7
|
+
await safeRecord(sink, {
|
|
8
|
+
agent: 'appliqation-explorer',
|
|
9
|
+
subcommand: 'explore',
|
|
10
|
+
startedAt,
|
|
11
|
+
endedAt,
|
|
12
|
+
durationMillis: endedAt - startedAt,
|
|
13
|
+
model,
|
|
14
|
+
usage,
|
|
15
|
+
turns: result?.turns,
|
|
16
|
+
budgetExceeded: result?.budgetExceeded,
|
|
17
|
+
// Never based on what the report found — budgetExceeded means the pass
|
|
18
|
+
// ended early, an unrelated failure to explore() throwing outright.
|
|
19
|
+
exitCode: result ? (result.budgetExceeded ? 1 : 0) : 1,
|
|
20
|
+
outcome: result
|
|
21
|
+
? { prompt, projectId, siteUrl, turns: result.turns, budgetExceeded: result.budgetExceeded, report: result.report }
|
|
22
|
+
: { prompt, projectId, siteUrl, error: true },
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/cli/audit.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,uEAAuE;AACvE,wDAAwD;AAExD,OAAO,EAAE,UAAU,EAAoC,MAAM,yBAAyB,CAAC;AAgBvF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAA0B;IAC/D,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC5F,MAAM,UAAU,CAAC,IAAI,EAAE;QACrB,KAAK,EAAE,sBAAsB;QAC7B,UAAU,EAAE,SAAS;QACrB,SAAS;QACT,OAAO;QACP,cAAc,EAAE,OAAO,GAAG,SAAS;QACnC,KAAK;QACL,KAAK;QACL,KAAK,EAAE,MAAM,EAAE,KAAK;QACpB,cAAc,EAAE,MAAM,EAAE,cAAc;QACtC,uEAAuE;QACvE,oEAAoE;QACpE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,OAAO,EAAE,MAAM;YACb,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;YACnH,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE;KAChD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `explore`: run appq's real appq:runman exploratory-QA workflow headlessly
|
|
3
|
+
// against a live target. See src/orchestrator/explore.ts for the actual
|
|
4
|
+
// mechanism; this file is just Commander wiring + result rendering.
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { createMcpClient, createAnthropicAdapter, createOpenAiAdapter, createUsageAccumulator } from '@appliqation/agent-core';
|
|
7
|
+
import { config, resolveProvider, resolveModel } from '../config/env.js';
|
|
8
|
+
import { explore } from '../orchestrator/explore.js';
|
|
9
|
+
import { recordExploreRun } from './audit.js';
|
|
10
|
+
import { printJsonSummary, printHumanSummary, exitCodeFor } from './output.js';
|
|
11
|
+
const client = createMcpClient({ origin: config.appqOrigin, apiKey: config.appqApiKey() });
|
|
12
|
+
function buildAdapter() {
|
|
13
|
+
const provider = resolveProvider();
|
|
14
|
+
const model = resolveModel();
|
|
15
|
+
return provider === 'anthropic'
|
|
16
|
+
? createAnthropicAdapter(config.anthropicApiKey, model, config.anthropicMaxTokens)
|
|
17
|
+
: createOpenAiAdapter(config.openaiApiKey, model, config.openaiMaxOutputTokens);
|
|
18
|
+
}
|
|
19
|
+
function logEvent(prefix) {
|
|
20
|
+
return (e) => {
|
|
21
|
+
if (e.type === 'assistant') {
|
|
22
|
+
const text = (e.detail ?? '').trim();
|
|
23
|
+
if (text)
|
|
24
|
+
console.error(`${prefix}[thinking] ${text}`);
|
|
25
|
+
}
|
|
26
|
+
else if (e.type === 'tool') {
|
|
27
|
+
const d = e.detail;
|
|
28
|
+
console.error(`${prefix}[tool] ${d.name} -> ${d.result.slice(0, 300)}`);
|
|
29
|
+
}
|
|
30
|
+
else if (e.type === 'log') {
|
|
31
|
+
console.error(`${prefix}[log] ${e.detail}`);
|
|
32
|
+
}
|
|
33
|
+
else if (e.type === 'usage') {
|
|
34
|
+
const u = e.detail;
|
|
35
|
+
const cacheNote = u.cacheReadTokens
|
|
36
|
+
? ` (${u.cacheReadTokens} from cache)`
|
|
37
|
+
: u.cacheWriteTokens
|
|
38
|
+
? ` (${u.cacheWriteTokens} written to cache)`
|
|
39
|
+
: '';
|
|
40
|
+
console.error(`${prefix}[usage] in=${u.inputTokens} out=${u.outputTokens}${cacheNote}`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const program = new Command();
|
|
45
|
+
program
|
|
46
|
+
.name('appliqation-explorer')
|
|
47
|
+
.description("Run Appliqation's exploratory-QA workflow (appq:runman) headlessly against a live app under test.");
|
|
48
|
+
program
|
|
49
|
+
.command('explore')
|
|
50
|
+
.description("Run appq:runman — surface mapping, a senior-QA heuristics pass, and mandatory security/network/caching/" +
|
|
51
|
+
'mobile probes — against a real target, always headlessly (interactive: "false", no confirmation gate). ' +
|
|
52
|
+
'Read-only end to end: offered appq context tools plus enrich_project_context, but its own attempted ' +
|
|
53
|
+
'action=write persistence at the end of the workflow is refused, not honored — see README.md.')
|
|
54
|
+
.requiredOption('--prompt <text>', 'plain-English exploration intent — can embed a URL')
|
|
55
|
+
.option('--project-id <id>', 'appq project id — enables reading persistent project-context memory')
|
|
56
|
+
.option('--site-url <url>', "override the URL appq:runman would otherwise resolve on its own")
|
|
57
|
+
.option('--max-steps <n>', 'override EXPLORE_MAX_STEPS for this run')
|
|
58
|
+
.option('--max-pages <n>', 'override EXPLORE_MAX_PAGES for this run')
|
|
59
|
+
.option('--max-minutes <n>', 'override EXPLORE_MAX_MINUTES for this run')
|
|
60
|
+
.option('--json', 'print a single structured JSON summary on stdout instead of a human-readable report')
|
|
61
|
+
.option('--ci', 'shorthand for --json')
|
|
62
|
+
.action(async (opts) => {
|
|
63
|
+
const json = (opts.json ?? false) || (opts.ci ?? false);
|
|
64
|
+
const adapter = buildAdapter();
|
|
65
|
+
const projectId = opts.projectId !== undefined ? Number(opts.projectId) : undefined;
|
|
66
|
+
const startedAt = Date.now();
|
|
67
|
+
const usage = createUsageAccumulator();
|
|
68
|
+
const baseLog = logEvent('');
|
|
69
|
+
let result;
|
|
70
|
+
try {
|
|
71
|
+
result = await explore({
|
|
72
|
+
client,
|
|
73
|
+
adapter,
|
|
74
|
+
prompt: opts.prompt,
|
|
75
|
+
projectId,
|
|
76
|
+
siteUrl: opts.siteUrl,
|
|
77
|
+
maxSteps: opts.maxSteps ? Number(opts.maxSteps) : config.exploreMaxSteps,
|
|
78
|
+
maxPages: opts.maxPages ? Number(opts.maxPages) : config.exploreMaxPages,
|
|
79
|
+
maxMinutes: opts.maxMinutes ? Number(opts.maxMinutes) : config.exploreMaxMinutes,
|
|
80
|
+
budget: config.budget,
|
|
81
|
+
ringBufferCap: config.evidenceRingBufferCap,
|
|
82
|
+
onEvent: (e) => {
|
|
83
|
+
baseLog(e);
|
|
84
|
+
if (e.type === 'usage')
|
|
85
|
+
usage.onUsage(e.detail);
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
// Audit write happens whether the run succeeded or threw — see
|
|
91
|
+
// @appliqation/agent-core's audit/sink.ts: safeRecord() (used
|
|
92
|
+
// inside recordExploreRun) never lets a failed/unreachable audit
|
|
93
|
+
// sink affect this process's real outcome, and this finally never
|
|
94
|
+
// blocks the throw below from propagating unchanged.
|
|
95
|
+
await recordExploreRun({
|
|
96
|
+
sink: config.auditSink,
|
|
97
|
+
startedAt,
|
|
98
|
+
endedAt: Date.now(),
|
|
99
|
+
model: resolveModel(),
|
|
100
|
+
usage: usage.totals(),
|
|
101
|
+
prompt: opts.prompt,
|
|
102
|
+
projectId,
|
|
103
|
+
siteUrl: opts.siteUrl,
|
|
104
|
+
result,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const summary = {
|
|
108
|
+
prompt: opts.prompt,
|
|
109
|
+
projectId,
|
|
110
|
+
siteUrl: opts.siteUrl,
|
|
111
|
+
turns: result.turns,
|
|
112
|
+
budgetExceeded: result.budgetExceeded,
|
|
113
|
+
report: result.report,
|
|
114
|
+
};
|
|
115
|
+
if (json)
|
|
116
|
+
printJsonSummary(summary);
|
|
117
|
+
else
|
|
118
|
+
printHumanSummary(summary);
|
|
119
|
+
process.exitCode = exitCodeFor(summary);
|
|
120
|
+
});
|
|
121
|
+
program.parseAsync(process.argv);
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// --json/--ci's renderer. Unlike appliqation-scriptgen/-defect-fix,
|
|
2
|
+
// "found bugs" is not a failure condition here — that's this agent's whole
|
|
3
|
+
// job. exitCodeFor() is non-zero only when the pass itself didn't
|
|
4
|
+
// complete (budgetExceeded), never based on what the report says it found.
|
|
5
|
+
export function printJsonSummary(summary) {
|
|
6
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
7
|
+
}
|
|
8
|
+
export function printHumanSummary(summary) {
|
|
9
|
+
console.log(`\n=== Exploration: "${summary.prompt}" ===\n`);
|
|
10
|
+
console.log(summary.report);
|
|
11
|
+
console.log(`\n(${summary.turns} turns, budget exceeded: ${summary.budgetExceeded})`);
|
|
12
|
+
if (summary.budgetExceeded) {
|
|
13
|
+
console.log(' Pass ended early on its own budget cap — the report above may be incomplete.');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** 1 only when the pass itself didn't complete — never based on what the report found. */
|
|
17
|
+
export function exitCodeFor(summary) {
|
|
18
|
+
return summary.budgetExceeded ? 1 : 0;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,2EAA2E;AAC3E,kEAAkE;AAClE,2EAA2E;AAW3E,MAAM,UAAU,gBAAgB,CAAC,OAAuB;IACtD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAuB;IACvD,OAAO,CAAC,GAAG,CAAC,uBAAuB,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,KAAK,4BAA4B,OAAO,CAAC,cAAc,GAAG,CAAC,CAAC;IACtF,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAAC;IAChG,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,WAAW,CAAC,OAAuB;IACjD,OAAO,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { DEFAULT_ANTHROPIC_MODEL, DEFAULT_OPENAI_MODEL } from '@appliqation/agent-core/providers';
|
|
3
|
+
import { required, optional } from '@appliqation/agent-core/config';
|
|
4
|
+
import { resolveAuditSink } from '@appliqation/agent-core/audit';
|
|
5
|
+
export const config = {
|
|
6
|
+
appqOrigin: optional('APPQ_ORIGIN') ?? 'https://appq.appliqation.io',
|
|
7
|
+
appqApiKey: () => required('APPQ_API_KEY'),
|
|
8
|
+
anthropicApiKey: optional('ANTHROPIC_API_KEY'),
|
|
9
|
+
openaiApiKey: optional('OPENAI_API_KEY'),
|
|
10
|
+
anthropicModel: optional('ANTHROPIC_MODEL'),
|
|
11
|
+
openaiModel: optional('OPENAI_MODEL'),
|
|
12
|
+
anthropicMaxTokens: Number(optional('ANTHROPIC_MAX_TOKENS') ?? 8192),
|
|
13
|
+
openaiMaxOutputTokens: Number(optional('OPENAI_MAX_OUTPUT_TOKENS') ?? 8192),
|
|
14
|
+
// appq:runman's own self-regulated budget (max_steps/max_pages/max_minutes
|
|
15
|
+
// args) — what the model is actually told to respect. Defaults match the
|
|
16
|
+
// workflow's own (RunmanPrompt.php).
|
|
17
|
+
exploreMaxSteps: Number(optional('EXPLORE_MAX_STEPS') ?? 50),
|
|
18
|
+
exploreMaxPages: Number(optional('EXPLORE_MAX_PAGES') ?? 12),
|
|
19
|
+
exploreMaxMinutes: Number(optional('EXPLORE_MAX_MINUTES') ?? 15),
|
|
20
|
+
// A code-enforced backstop in case the model doesn't honor the
|
|
21
|
+
// prompt-level limits above — set generously above them, not equal to
|
|
22
|
+
// them (unlike appliqation-scriptgen's ~infinite maxPages, this agent
|
|
23
|
+
// really does drive browser_navigate, so the cap has to be real).
|
|
24
|
+
budget: {
|
|
25
|
+
maxCalls: Number(optional('BUDGET_MAX_CALLS') ?? 150),
|
|
26
|
+
maxPages: Number(optional('BUDGET_MAX_PAGES') ?? 40),
|
|
27
|
+
maxMillis: Number(optional('BUDGET_MAX_MILLIS') ?? 25 * 60 * 1000),
|
|
28
|
+
maxTurns: Number(optional('BUDGET_MAX_TURNS') ?? 80),
|
|
29
|
+
},
|
|
30
|
+
evidenceRingBufferCap: Number(optional('EVIDENCE_RING_BUFFER_CAP') ?? 500),
|
|
31
|
+
// Observability, entirely opt-in — see @appliqation/agent-core's audit/sink.ts.
|
|
32
|
+
// Nothing is recorded anywhere unless AUDIT_MONGO_URI or AUDIT_JSONL_PATH is
|
|
33
|
+
// actually set; resolveAuditSink() falls back to a no-op sink otherwise.
|
|
34
|
+
auditSink: resolveAuditSink({
|
|
35
|
+
auditMongoUri: optional('AUDIT_MONGO_URI'),
|
|
36
|
+
auditMongoDb: optional('AUDIT_MONGO_DB'),
|
|
37
|
+
auditMongoCollection: optional('AUDIT_MONGO_COLLECTION'),
|
|
38
|
+
auditJsonlPath: optional('AUDIT_JSONL_PATH'),
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
export function resolveProvider() {
|
|
42
|
+
if (config.anthropicApiKey)
|
|
43
|
+
return 'anthropic';
|
|
44
|
+
if (config.openaiApiKey)
|
|
45
|
+
return 'openai';
|
|
46
|
+
throw new Error('Set ANTHROPIC_API_KEY or OPENAI_API_KEY');
|
|
47
|
+
}
|
|
48
|
+
export function resolveModel() {
|
|
49
|
+
const provider = resolveProvider();
|
|
50
|
+
return provider === 'anthropic' ? (config.anthropicModel ?? DEFAULT_ANTHROPIC_MODEL) : (config.openaiModel ?? DEFAULT_OPENAI_MODEL);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/config/env.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAClG,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,IAAI,6BAA6B;IACpE,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;IAC1C,eAAe,EAAE,QAAQ,CAAC,mBAAmB,CAAC;IAC9C,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC;IACxC,cAAc,EAAE,QAAQ,CAAC,iBAAiB,CAAC;IAC3C,WAAW,EAAE,QAAQ,CAAC,cAAc,CAAC;IACrC,kBAAkB,EAAE,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,IAAI,IAAI,CAAC;IACpE,qBAAqB,EAAE,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAC,IAAI,IAAI,CAAC;IAE3E,2EAA2E;IAC3E,yEAAyE;IACzE,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC;IAC5D,eAAe,EAAE,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC;IAC5D,iBAAiB,EAAE,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,EAAE,CAAC;IAEhE,+DAA+D;IAC/D,sEAAsE;IACtE,sEAAsE;IACtE,kEAAkE;IAClE,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,GAAG,CAAC;QACrD,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC;QACpD,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAClE,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC;KACrD;IAED,qBAAqB,EAAE,MAAM,CAAC,QAAQ,CAAC,0BAA0B,CAAC,IAAI,GAAG,CAAC;IAE1E,gFAAgF;IAChF,6EAA6E;IAC7E,yEAAyE;IACzE,SAAS,EAAE,gBAAgB,CAAC;QAC1B,aAAa,EAAE,QAAQ,CAAC,iBAAiB,CAAC;QAC1C,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC;QACxC,oBAAoB,EAAE,QAAQ,CAAC,wBAAwB,CAAC;QACxD,cAAc,EAAE,QAAQ,CAAC,kBAAkB,CAAC;KAC7C,CAAC;CACH,CAAC;AAEF,MAAM,UAAU,eAAe;IAC7B,IAAI,MAAM,CAAC,eAAe;QAAE,OAAO,WAAW,CAAC;IAC/C,IAAI,MAAM,CAAC,YAAY;QAAE,OAAO,QAAQ,CAAC;IACzC,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,cAAc,IAAI,uBAAuB,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,IAAI,oBAAoB,CAAC,CAAC;AACtI,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Calls appq's real appq:runman workflow through the shared engine, headlessly
|
|
2
|
+
// (interactive: "false" — no human to answer a mid-run confirmation), offering
|
|
3
|
+
// it real browser_* tools plus a read-only appq context allowlist. The
|
|
4
|
+
// workflow's own methodology (7 phases: prerequisites/URL resolution, context
|
|
5
|
+
// gathering, surface mapping, a senior-QA heuristics pass plus mandatory
|
|
6
|
+
// security/network/caching/mobile probes, an evidence-discipline gate, and a
|
|
7
|
+
// findings report) lives entirely server-side — nothing here duplicates it.
|
|
8
|
+
//
|
|
9
|
+
// Deliberately doesn't structurally parse a bug count or severity out of the
|
|
10
|
+
// returned Markdown report — this agent's job is producing a report for a
|
|
11
|
+
// human or appliqation-autopilot to read and reason about, not a pass/fail
|
|
12
|
+
// verdict a pipeline gates on. budgetExceeded (from LoopResult, unchanged) is
|
|
13
|
+
// the only thing that decides the CLI's exit code — see cli/index.ts.
|
|
14
|
+
import { chromium } from 'playwright';
|
|
15
|
+
import { PlaywrightBrowserTools, BROWSER_TOOL_DEFS, fetchAppqToolDefs, createGatedAppqDispatcher, createReadOnlyProjectContextDispatcher, runWorkflow, } from '@appliqation/agent-core';
|
|
16
|
+
import { READONLY_APPQ_TOOLS } from '../tools/safety.js';
|
|
17
|
+
export async function explore(opts) {
|
|
18
|
+
const appqToolDefs = await fetchAppqToolDefs(opts.client, READONLY_APPQ_TOOLS);
|
|
19
|
+
// Argument-level gate applied outermost — see @appliqation/agent-core's
|
|
20
|
+
// tools/projectContext.ts — so this agent's own attempted
|
|
21
|
+
// enrich_project_context write (appq:runman's own Phase 6 instruction,
|
|
22
|
+
// meant for an interactive session with a human at the confirmation gate)
|
|
23
|
+
// is refused before it ever reaches appq, not silently honored just
|
|
24
|
+
// because nothing is watching this particular invocation.
|
|
25
|
+
const gatedAppq = createReadOnlyProjectContextDispatcher(createGatedAppqDispatcher(opts.client, READONLY_APPQ_TOOLS));
|
|
26
|
+
const browser = await chromium.launch();
|
|
27
|
+
const page = await browser.newPage();
|
|
28
|
+
try {
|
|
29
|
+
const browserTools = new PlaywrightBrowserTools(page, opts.ringBufferCap);
|
|
30
|
+
const dispatch = async (name, args) => {
|
|
31
|
+
if (name.startsWith('browser_'))
|
|
32
|
+
return browserTools.dispatch(name, args);
|
|
33
|
+
return gatedAppq(name, args);
|
|
34
|
+
};
|
|
35
|
+
const promptArgs = {
|
|
36
|
+
prompt: opts.prompt,
|
|
37
|
+
interactive: 'false',
|
|
38
|
+
max_steps: opts.maxSteps,
|
|
39
|
+
max_pages: opts.maxPages,
|
|
40
|
+
max_minutes: opts.maxMinutes,
|
|
41
|
+
};
|
|
42
|
+
if (opts.projectId !== undefined)
|
|
43
|
+
promptArgs.project_id = opts.projectId;
|
|
44
|
+
if (opts.siteUrl)
|
|
45
|
+
promptArgs.site_url = opts.siteUrl;
|
|
46
|
+
const seedLines = [`Exploration intent: ${opts.prompt}`];
|
|
47
|
+
if (opts.siteUrl)
|
|
48
|
+
seedLines.push(`URL under test: ${opts.siteUrl}`);
|
|
49
|
+
if (opts.projectId !== undefined)
|
|
50
|
+
seedLines.push(`Project ID: ${opts.projectId}`);
|
|
51
|
+
seedLines.push('Begin now — start with browser_snapshot.');
|
|
52
|
+
return await runWorkflow({
|
|
53
|
+
source: { kind: 'appq', name: 'appq:runman', args: promptArgs },
|
|
54
|
+
fetchPrompt: opts.client.fetchPrompt,
|
|
55
|
+
seedMessage: seedLines.join('\n'),
|
|
56
|
+
tools: [...BROWSER_TOOL_DEFS, ...appqToolDefs],
|
|
57
|
+
dispatch,
|
|
58
|
+
adapter: opts.adapter,
|
|
59
|
+
budget: opts.budget,
|
|
60
|
+
onEvent: opts.onEvent,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
finally {
|
|
64
|
+
await browser.close();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=explore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../src/orchestrator/explore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// This agent's own domain knowledge of which appq tools it may touch — the
|
|
2
|
+
// enforcement mechanism (assertToolAllowed / the gated dispatcher) lives in
|
|
3
|
+
// @appliqation/agent-core, shared with every sibling agent; only the
|
|
4
|
+
// allowlist content is local. Genuinely read-only end to end, including
|
|
5
|
+
// enrich_project_context: it's offered here because it has a real read
|
|
6
|
+
// mode this agent needs (known_issues/high_risk_areas inform what's worth
|
|
7
|
+
// exploring), but @appliqation/agent-core's createReadOnlyProjectContextDispatcher
|
|
8
|
+
// refuses its action=write mode unconditionally — see cli/index.ts and
|
|
9
|
+
// README.md's Safety section for why this agent, unlike an interactive
|
|
10
|
+
// appq:runman session, never gets to use it.
|
|
11
|
+
export const READONLY_APPQ_TOOLS = new Set([
|
|
12
|
+
'get_scenario',
|
|
13
|
+
'get_coverage_analysis',
|
|
14
|
+
'get_defects',
|
|
15
|
+
'get_failure_patterns',
|
|
16
|
+
'get_quality_context',
|
|
17
|
+
'get_evidence_summary',
|
|
18
|
+
'get_run_evidence',
|
|
19
|
+
'search_tests',
|
|
20
|
+
'get_project_settings',
|
|
21
|
+
'enrich_project_context',
|
|
22
|
+
'get_validation_targets',
|
|
23
|
+
]);
|
|
24
|
+
//# sourceMappingURL=safety.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/tools/safety.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,qEAAqE;AACrE,wEAAwE;AACxE,uEAAuE;AACvE,0EAA0E;AAC1E,mFAAmF;AACnF,uEAAuE;AACvE,uEAAuE;AACvE,6CAA6C;AAE7C,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IACzC,cAAc;IACd,uBAAuB;IACvB,aAAa;IACb,sBAAsB;IACtB,qBAAqB;IACrB,sBAAsB;IACtB,kBAAkB;IAClB,cAAc;IACd,sBAAsB;IACtB,wBAAwB;IACxB,wBAAwB;CACzB,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@appliqation/explorer",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Standalone agent that runs Appliqation's exploratory-QA workflow (appq:runman) headlessly against a live app under test \u2014 the same senior-QA heuristics pass, without a human at the confirmation gate.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"appliqation-explorer": "./dist/cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p tsconfig.build.json",
|
|
19
|
+
"dev": "tsx src/cli/index.ts",
|
|
20
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
21
|
+
"lint": "eslint src --ext .ts",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@appliqation/agent-core": "^0.1.0",
|
|
27
|
+
"commander": "^13.1.0",
|
|
28
|
+
"dotenv": "^16.4.7",
|
|
29
|
+
"playwright": "^1.51.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.13.10",
|
|
33
|
+
"tsx": "^4.19.3",
|
|
34
|
+
"typescript": "^5.8.2",
|
|
35
|
+
"vitest": "^3.2.7"
|
|
36
|
+
}
|
|
37
|
+
}
|