swipium 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +295 -0
- package/dist/appMap/automationLink.js +74 -0
- package/dist/appMap/automationLink.js.map +1 -0
- package/dist/appMap/build.js +193 -0
- package/dist/appMap/build.js.map +1 -0
- package/dist/appMap/codeIndex.js +73 -0
- package/dist/appMap/codeIndex.js.map +1 -0
- package/dist/appMap/featureModel.js +83 -0
- package/dist/appMap/featureModel.js.map +1 -0
- package/dist/appMap/firstRunApply.js +131 -0
- package/dist/appMap/firstRunApply.js.map +1 -0
- package/dist/appMap/fsWalk.js +75 -0
- package/dist/appMap/fsWalk.js.map +1 -0
- package/dist/appMap/issues.js +227 -0
- package/dist/appMap/issues.js.map +1 -0
- package/dist/appMap/migrations.js +87 -0
- package/dist/appMap/migrations.js.map +1 -0
- package/dist/appMap/prelaunch.js +66 -0
- package/dist/appMap/prelaunch.js.map +1 -0
- package/dist/appMap/projectRegistry.js +70 -0
- package/dist/appMap/projectRegistry.js.map +1 -0
- package/dist/appMap/provenance.js +52 -0
- package/dist/appMap/provenance.js.map +1 -0
- package/dist/appMap/query.js +118 -0
- package/dist/appMap/query.js.map +1 -0
- package/dist/appMap/runtimeMerge.js +207 -0
- package/dist/appMap/runtimeMerge.js.map +1 -0
- package/dist/appMap/schema.js +65 -0
- package/dist/appMap/schema.js.map +1 -0
- package/dist/appMap/screenMatch.js +75 -0
- package/dist/appMap/screenMatch.js.map +1 -0
- package/dist/appMap/staticScan.js +614 -0
- package/dist/appMap/staticScan.js.map +1 -0
- package/dist/appMap/store.js +173 -0
- package/dist/appMap/store.js.map +1 -0
- package/dist/appMap/tsAstScan.js +184 -0
- package/dist/appMap/tsAstScan.js.map +1 -0
- package/dist/artifacts/bundletool.js +199 -0
- package/dist/artifacts/bundletool.js.map +1 -0
- package/dist/artifacts/resolve.js +388 -0
- package/dist/artifacts/resolve.js.map +1 -0
- package/dist/automationGen/appiumModel.js +129 -0
- package/dist/automationGen/appiumModel.js.map +1 -0
- package/dist/automationGen/ciEmitter.js +80 -0
- package/dist/automationGen/ciEmitter.js.map +1 -0
- package/dist/automationGen/jsEmitter.js +440 -0
- package/dist/automationGen/jsEmitter.js.map +1 -0
- package/dist/automationGen/packagePatch.js +56 -0
- package/dist/automationGen/packagePatch.js.map +1 -0
- package/dist/automationGen/projectProfile.js +317 -0
- package/dist/automationGen/projectProfile.js.map +1 -0
- package/dist/automationGen/pythonEmitter.js +386 -0
- package/dist/automationGen/pythonEmitter.js.map +1 -0
- package/dist/automationGen/readmeEmitter.js +66 -0
- package/dist/automationGen/readmeEmitter.js.map +1 -0
- package/dist/automationGen/suitePlan.js +94 -0
- package/dist/automationGen/suitePlan.js.map +1 -0
- package/dist/automationGen/validation.js +150 -0
- package/dist/automationGen/validation.js.map +1 -0
- package/dist/build/parseBuildLog.js +119 -0
- package/dist/build/parseBuildLog.js.map +1 -0
- package/dist/build/plan.js +150 -0
- package/dist/build/plan.js.map +1 -0
- package/dist/ci/preflight.js +85 -0
- package/dist/ci/preflight.js.map +1 -0
- package/dist/cli/init.js +105 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/scan.js +85 -0
- package/dist/cli/scan.js.map +1 -0
- package/dist/cli/suite.js +85 -0
- package/dist/cli/suite.js.map +1 -0
- package/dist/cli/verify.js +62 -0
- package/dist/cli/verify.js.map +1 -0
- package/dist/consent/consent.js +43 -0
- package/dist/consent/consent.js.map +1 -0
- package/dist/context/detect.js +156 -0
- package/dist/context/detect.js.map +1 -0
- package/dist/context/findApps.js +198 -0
- package/dist/context/findApps.js.map +1 -0
- package/dist/context/projectRoot.js +41 -0
- package/dist/context/projectRoot.js.map +1 -0
- package/dist/context/scan.js +167 -0
- package/dist/context/scan.js.map +1 -0
- package/dist/core/target.js +115 -0
- package/dist/core/target.js.map +1 -0
- package/dist/core/targetPlan.js +140 -0
- package/dist/core/targetPlan.js.map +1 -0
- package/dist/drivers/DirectDriver.js +228 -0
- package/dist/drivers/DirectDriver.js.map +1 -0
- package/dist/drivers/Driver.js +4 -0
- package/dist/drivers/Driver.js.map +1 -0
- package/dist/drivers/SimctlDriver.js +127 -0
- package/dist/drivers/SimctlDriver.js.map +1 -0
- package/dist/drivers/WdaDriver.js +250 -0
- package/dist/drivers/WdaDriver.js.map +1 -0
- package/dist/explore/candidates.js +93 -0
- package/dist/explore/candidates.js.map +1 -0
- package/dist/explore/graph.js +116 -0
- package/dist/explore/graph.js.map +1 -0
- package/dist/explore/memory.js +35 -0
- package/dist/explore/memory.js.map +1 -0
- package/dist/explore/planner.js +105 -0
- package/dist/explore/planner.js.map +1 -0
- package/dist/explore/policy.js +85 -0
- package/dist/explore/policy.js.map +1 -0
- package/dist/explore/runner.js +475 -0
- package/dist/explore/runner.js.map +1 -0
- package/dist/explore/signatures.js +35 -0
- package/dist/explore/signatures.js.map +1 -0
- package/dist/explore/suite.js +55 -0
- package/dist/explore/suite.js.map +1 -0
- package/dist/featureTesting/executionBootstrap.js +140 -0
- package/dist/featureTesting/executionBootstrap.js.map +1 -0
- package/dist/firstRun/authStateMachine.js +83 -0
- package/dist/firstRun/authStateMachine.js.map +1 -0
- package/dist/firstRun/classifyScreen.js +201 -0
- package/dist/firstRun/classifyScreen.js.map +1 -0
- package/dist/firstRun/firstRunPlanner.js +207 -0
- package/dist/firstRun/firstRunPlanner.js.map +1 -0
- package/dist/firstRun/firstRunRunner.js +331 -0
- package/dist/firstRun/firstRunRunner.js.map +1 -0
- package/dist/firstRun/generatedDataPolicy.js +215 -0
- package/dist/firstRun/generatedDataPolicy.js.map +1 -0
- package/dist/firstRun/inputPlanner.js +67 -0
- package/dist/firstRun/inputPlanner.js.map +1 -0
- package/dist/firstRun/onboardingStateMachine.js +46 -0
- package/dist/firstRun/onboardingStateMachine.js.map +1 -0
- package/dist/firstRun/paywallPolicy.js +54 -0
- package/dist/firstRun/paywallPolicy.js.map +1 -0
- package/dist/firstRun/types.js +7 -0
- package/dist/firstRun/types.js.map +1 -0
- package/dist/fixtures/catalog.js +131 -0
- package/dist/fixtures/catalog.js.map +1 -0
- package/dist/flows/discover.js +18 -0
- package/dist/flows/discover.js.map +1 -0
- package/dist/flows/generate.js +211 -0
- package/dist/flows/generate.js.map +1 -0
- package/dist/flows/lint.js +97 -0
- package/dist/flows/lint.js.map +1 -0
- package/dist/flows/pack.js +68 -0
- package/dist/flows/pack.js.map +1 -0
- package/dist/flows/run.js +738 -0
- package/dist/flows/run.js.map +1 -0
- package/dist/flows/schema.js +240 -0
- package/dist/flows/schema.js.map +1 -0
- package/dist/flows/seedExec.js +108 -0
- package/dist/flows/seedExec.js.map +1 -0
- package/dist/flows/templates.js +155 -0
- package/dist/flows/templates.js.map +1 -0
- package/dist/flows/waitGuards.js +12 -0
- package/dist/flows/waitGuards.js.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/ios/signing.js +182 -0
- package/dist/ios/signing.js.map +1 -0
- package/dist/issues/classify.js +186 -0
- package/dist/issues/classify.js.map +1 -0
- package/dist/issues/fingerprint.js +130 -0
- package/dist/issues/fingerprint.js.map +1 -0
- package/dist/issues/index.js +240 -0
- package/dist/issues/index.js.map +1 -0
- package/dist/issues/metrics.js +155 -0
- package/dist/issues/metrics.js.map +1 -0
- package/dist/issues/recurrence.js +193 -0
- package/dist/issues/recurrence.js.map +1 -0
- package/dist/issues/report.js +110 -0
- package/dist/issues/report.js.map +1 -0
- package/dist/issues/reportBridge.js +119 -0
- package/dist/issues/reportBridge.js.map +1 -0
- package/dist/issues/schema.js +90 -0
- package/dist/issues/schema.js.map +1 -0
- package/dist/issues/sourceRevision.js +108 -0
- package/dist/issues/sourceRevision.js.map +1 -0
- package/dist/issues/store.js +155 -0
- package/dist/issues/store.js.map +1 -0
- package/dist/lib/android.js +278 -0
- package/dist/lib/android.js.map +1 -0
- package/dist/lib/commandTemplate.js +55 -0
- package/dist/lib/commandTemplate.js.map +1 -0
- package/dist/lib/coordSpace.js +23 -0
- package/dist/lib/coordSpace.js.map +1 -0
- package/dist/lib/device.js +87 -0
- package/dist/lib/device.js.map +1 -0
- package/dist/lib/gitignore.js +22 -0
- package/dist/lib/gitignore.js.map +1 -0
- package/dist/lib/image.js +97 -0
- package/dist/lib/image.js.map +1 -0
- package/dist/lib/logger.js +8 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/metroState.js +45 -0
- package/dist/lib/metroState.js.map +1 -0
- package/dist/lib/needsInput.js +201 -0
- package/dist/lib/needsInput.js.map +1 -0
- package/dist/lib/png.js +103 -0
- package/dist/lib/png.js.map +1 -0
- package/dist/lib/redact.js +21 -0
- package/dist/lib/redact.js.map +1 -0
- package/dist/lib/result.js +87 -0
- package/dist/lib/result.js.map +1 -0
- package/dist/lib/schemaHash.js +65 -0
- package/dist/lib/schemaHash.js.map +1 -0
- package/dist/lib/sensitive.js +13 -0
- package/dist/lib/sensitive.js.map +1 -0
- package/dist/lib/simctl.js +149 -0
- package/dist/lib/simctl.js.map +1 -0
- package/dist/lib/spawn.js +144 -0
- package/dist/lib/spawn.js.map +1 -0
- package/dist/lib/wda.js +347 -0
- package/dist/lib/wda.js.map +1 -0
- package/dist/lib/wdaConfig.js +69 -0
- package/dist/lib/wdaConfig.js.map +1 -0
- package/dist/lib/wdaTune.js +58 -0
- package/dist/lib/wdaTune.js.map +1 -0
- package/dist/oracle/auth.js +22 -0
- package/dist/oracle/auth.js.map +1 -0
- package/dist/oracle/failures.js +193 -0
- package/dist/oracle/failures.js.map +1 -0
- package/dist/oracle/health.js +123 -0
- package/dist/oracle/health.js.map +1 -0
- package/dist/oracle/record.js +36 -0
- package/dist/oracle/record.js.map +1 -0
- package/dist/orchestration/envelope.js +52 -0
- package/dist/orchestration/envelope.js.map +1 -0
- package/dist/orchestration/goal.js +98 -0
- package/dist/orchestration/goal.js.map +1 -0
- package/dist/plan/plan.js +124 -0
- package/dist/plan/plan.js.map +1 -0
- package/dist/prompts/index.js +63 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/report/artifactManifest.js +44 -0
- package/dist/report/artifactManifest.js.map +1 -0
- package/dist/report/coverage.js +60 -0
- package/dist/report/coverage.js.map +1 -0
- package/dist/report/evidence.js +84 -0
- package/dist/report/evidence.js.map +1 -0
- package/dist/report/export.js +447 -0
- package/dist/report/export.js.map +1 -0
- package/dist/report/flake.js +61 -0
- package/dist/report/flake.js.map +1 -0
- package/dist/report/history.js +564 -0
- package/dist/report/history.js.map +1 -0
- package/dist/report/policy.js +98 -0
- package/dist/report/policy.js.map +1 -0
- package/dist/report/qaLevel.js +96 -0
- package/dist/report/qaLevel.js.map +1 -0
- package/dist/report/readiness.js +213 -0
- package/dist/report/readiness.js.map +1 -0
- package/dist/report/summary.js +42 -0
- package/dist/report/summary.js.map +1 -0
- package/dist/report/testCatalog.js +93 -0
- package/dist/report/testCatalog.js.map +1 -0
- package/dist/report/timing.js +37 -0
- package/dist/report/timing.js.map +1 -0
- package/dist/server.js +180 -0
- package/dist/server.js.map +1 -0
- package/dist/services/automationGenerate.js +60 -0
- package/dist/services/automationGenerate.js.map +1 -0
- package/dist/services/build.js +66 -0
- package/dist/services/build.js.map +1 -0
- package/dist/services/preflight.js +51 -0
- package/dist/services/preflight.js.map +1 -0
- package/dist/services/prepareAndroid.js +183 -0
- package/dist/services/prepareAndroid.js.map +1 -0
- package/dist/services/prepareIos.js +162 -0
- package/dist/services/prepareIos.js.map +1 -0
- package/dist/services/report.js +537 -0
- package/dist/services/report.js.map +1 -0
- package/dist/services/smoke.js +120 -0
- package/dist/services/smoke.js.map +1 -0
- package/dist/services/suiteGenerate.js +123 -0
- package/dist/services/suiteGenerate.js.map +1 -0
- package/dist/services/testSuiteKnowledge.js +150 -0
- package/dist/services/testSuiteKnowledge.js.map +1 -0
- package/dist/session/attach.js +47 -0
- package/dist/session/attach.js.map +1 -0
- package/dist/session/progress.js +56 -0
- package/dist/session/progress.js.map +1 -0
- package/dist/session/store.js +329 -0
- package/dist/session/store.js.map +1 -0
- package/dist/snapshot/overlays.js +132 -0
- package/dist/snapshot/overlays.js.map +1 -0
- package/dist/snapshot/parse.js +204 -0
- package/dist/snapshot/parse.js.map +1 -0
- package/dist/snapshot/present.js +12 -0
- package/dist/snapshot/present.js.map +1 -0
- package/dist/snapshot/settle.js +36 -0
- package/dist/snapshot/settle.js.map +1 -0
- package/dist/state/profile.js +318 -0
- package/dist/state/profile.js.map +1 -0
- package/dist/suite/compile.js +176 -0
- package/dist/suite/compile.js.map +1 -0
- package/dist/suite/lint.js +45 -0
- package/dist/suite/lint.js.map +1 -0
- package/dist/suite/pom.js +285 -0
- package/dist/suite/pom.js.map +1 -0
- package/dist/suite/testcase.js +87 -0
- package/dist/suite/testcase.js.map +1 -0
- package/dist/testSuite/generator.js +222 -0
- package/dist/testSuite/generator.js.map +1 -0
- package/dist/testSuite/history.js +44 -0
- package/dist/testSuite/history.js.map +1 -0
- package/dist/testSuite/issueLinks.js +96 -0
- package/dist/testSuite/issueLinks.js.map +1 -0
- package/dist/testSuite/merge.js +190 -0
- package/dist/testSuite/merge.js.map +1 -0
- package/dist/testSuite/schema.js +86 -0
- package/dist/testSuite/schema.js.map +1 -0
- package/dist/testSuite/store.js +116 -0
- package/dist/testSuite/store.js.map +1 -0
- package/dist/testSuite/traceability.js +55 -0
- package/dist/testSuite/traceability.js.map +1 -0
- package/dist/tools/act.js +457 -0
- package/dist/tools/act.js.map +1 -0
- package/dist/tools/agent.js +225 -0
- package/dist/tools/agent.js.map +1 -0
- package/dist/tools/appMap.js +317 -0
- package/dist/tools/appMap.js.map +1 -0
- package/dist/tools/assertVisual.js +74 -0
- package/dist/tools/assertVisual.js.map +1 -0
- package/dist/tools/automationGenerate.js +394 -0
- package/dist/tools/automationGenerate.js.map +1 -0
- package/dist/tools/capabilities.js +114 -0
- package/dist/tools/capabilities.js.map +1 -0
- package/dist/tools/clearOverlay.js +150 -0
- package/dist/tools/clearOverlay.js.map +1 -0
- package/dist/tools/detectContext.js +41 -0
- package/dist/tools/detectContext.js.map +1 -0
- package/dist/tools/doctor.js +116 -0
- package/dist/tools/doctor.js.map +1 -0
- package/dist/tools/explore.js +289 -0
- package/dist/tools/explore.js.map +1 -0
- package/dist/tools/firstRun.js +136 -0
- package/dist/tools/firstRun.js.map +1 -0
- package/dist/tools/flow.js +331 -0
- package/dist/tools/flow.js.map +1 -0
- package/dist/tools/flowGenerate.js +55 -0
- package/dist/tools/flowGenerate.js.map +1 -0
- package/dist/tools/getArtifact.js +39 -0
- package/dist/tools/getArtifact.js.map +1 -0
- package/dist/tools/health.js +41 -0
- package/dist/tools/health.js.map +1 -0
- package/dist/tools/ios.js +492 -0
- package/dist/tools/ios.js.map +1 -0
- package/dist/tools/jobs.js +20 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/network.js +50 -0
- package/dist/tools/network.js.map +1 -0
- package/dist/tools/note.js +69 -0
- package/dist/tools/note.js.map +1 -0
- package/dist/tools/plan.js +49 -0
- package/dist/tools/plan.js.map +1 -0
- package/dist/tools/prepareIosTarget.js +99 -0
- package/dist/tools/prepareIosTarget.js.map +1 -0
- package/dist/tools/prepareTarget.js +257 -0
- package/dist/tools/prepareTarget.js.map +1 -0
- package/dist/tools/report.js +42 -0
- package/dist/tools/report.js.map +1 -0
- package/dist/tools/screenRecord.js +24 -0
- package/dist/tools/screenRecord.js.map +1 -0
- package/dist/tools/screenshot.js +63 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/smoke.js +39 -0
- package/dist/tools/smoke.js.map +1 -0
- package/dist/tools/snapshot.js +129 -0
- package/dist/tools/snapshot.js.map +1 -0
- package/dist/tools/startSession.js +169 -0
- package/dist/tools/startSession.js.map +1 -0
- package/dist/tools/state.js +87 -0
- package/dist/tools/state.js.map +1 -0
- package/dist/tools/suite.js +412 -0
- package/dist/tools/suite.js.map +1 -0
- package/dist/tools/testThis.js +774 -0
- package/dist/tools/testThis.js.map +1 -0
- package/dist/tools/wda.js +477 -0
- package/dist/tools/wda.js.map +1 -0
- package/dist/version.js +62 -0
- package/dist/version.js.map +1 -0
- package/dist/visual/ocr.js +72 -0
- package/dist/visual/ocr.js.map +1 -0
- package/dist/visual/provider.js +75 -0
- package/dist/visual/provider.js.map +1 -0
- package/docs/README.md +19 -0
- package/docs/assets/swipium-lockup-ink-on-light.png +0 -0
- package/docs/mcp-server.md +135 -0
- package/docs/tools.md +130 -0
- package/package.json +70 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Shared Metro/dev-server readiness checks used by target preparation.
|
|
2
|
+
import net from 'node:net';
|
|
3
|
+
import { run } from './spawn.js';
|
|
4
|
+
export const METRO_PORT = 8081;
|
|
5
|
+
export function metroListening(port = METRO_PORT, host = '127.0.0.1', timeoutMs = 1500) {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
const socket = net.connect({ port, host });
|
|
8
|
+
const done = (v) => {
|
|
9
|
+
socket.destroy();
|
|
10
|
+
resolve(v);
|
|
11
|
+
};
|
|
12
|
+
socket.once('connect', () => done(true));
|
|
13
|
+
socket.once('error', () => done(false));
|
|
14
|
+
socket.setTimeout(timeoutMs, () => done(false));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export async function reverseSet(serial, port = METRO_PORT) {
|
|
18
|
+
try {
|
|
19
|
+
const r = await run('adb', ['-s', serial, 'reverse', '--list'], { timeoutMs: 5000 });
|
|
20
|
+
return r.stdout.includes(`tcp:${port}`);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Is Metro actually SERVING (not just a port open)? Hits the host-side packager status. */
|
|
27
|
+
export async function bundleServing(port = METRO_PORT) {
|
|
28
|
+
try {
|
|
29
|
+
const res = await fetch(`http://localhost:${port}/status`, { signal: AbortSignal.timeout(3000) });
|
|
30
|
+
const body = (await res.text()).trim();
|
|
31
|
+
return { serving: res.ok && /packager-status:running/.test(body), detail: `${res.status} ${body.slice(0, 40)}` };
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
return { serving: false, detail: String(e) };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export async function metroReadiness(serial, port = METRO_PORT) {
|
|
38
|
+
const [listening, rev, srv] = await Promise.all([
|
|
39
|
+
metroListening(port),
|
|
40
|
+
serial ? reverseSet(serial, port) : Promise.resolve(false),
|
|
41
|
+
bundleServing(port),
|
|
42
|
+
]);
|
|
43
|
+
return { listening, reverseSet: rev, serving: srv.serving, ready: listening && rev && srv.serving, detail: srv.detail };
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=metroState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metroState.js","sourceRoot":"","sources":["../../src/lib/metroState.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
// NeedsInput protocol (roadmap §3.2) — a single, consistent shape for the missing-input
|
|
2
|
+
// blockers a QA run hits, so an agent forwards ONE concise question to the user instead of
|
|
3
|
+
// improvising. It is NOT an error: the run is paused, recoverable, and resumable. The payload
|
|
4
|
+
// rides on a normal (ok:true) tool result with `needsInput:true`, and is also embeddable in a
|
|
5
|
+
// blocker via `embedNeedsInput`.
|
|
6
|
+
//
|
|
7
|
+
// Secret fields (passwords, OTPs, tokens) are flagged so the caller redacts them everywhere:
|
|
8
|
+
// once provided, the value goes into session.secrets and never appears in artifacts/logs.
|
|
9
|
+
//
|
|
10
|
+
// Developer 1 contract (Milestone B): EVERY NeedsInput response carries one concise question,
|
|
11
|
+
// typed fields (with secret flags), safe fallback options, the EXACT resume call, what Swipium
|
|
12
|
+
// already tried (`attempted`), and what happens if the user declines (`ifDeclined`). Agents ask
|
|
13
|
+
// one question — never a bundle of guesses — and resume deterministically.
|
|
14
|
+
import { currentResponseMode } from './result.js';
|
|
15
|
+
/** Default resume: hand the answer to qa_continue_from_blocker, which routes by kind. */
|
|
16
|
+
function resumeVia(kind) {
|
|
17
|
+
return { tool: 'qa_continue_from_blocker', args: { kind } };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The standardized QA questions (roadmap §3.2). Builders, not constants, so callers can splice
|
|
21
|
+
* in context (which app, which screen) while keeping the field/fallback/resume contract stable.
|
|
22
|
+
* `attempted` is left empty here and filled by qaNeedsInput from the live session.
|
|
23
|
+
*/
|
|
24
|
+
export const NeedsInput = {
|
|
25
|
+
credentials(context) {
|
|
26
|
+
return {
|
|
27
|
+
needsInput: true,
|
|
28
|
+
kind: 'credentials',
|
|
29
|
+
question: (context ? `${context} ` : '') +
|
|
30
|
+
'This app appears to require login. Provide test credentials, or ask Swipium to stay pre-login.',
|
|
31
|
+
fields: [
|
|
32
|
+
{ name: 'email', secret: false, description: 'Test account email/username' },
|
|
33
|
+
{ name: 'password', secret: true, description: 'Test account password' },
|
|
34
|
+
],
|
|
35
|
+
fallbackOptions: ['test pre-login only', 'use saved session', 'seed login state'],
|
|
36
|
+
resume: resumeVia('credentials'),
|
|
37
|
+
attempted: [],
|
|
38
|
+
ifDeclined: 'Swipium tests pre-login coverage only; authenticated flows are reported as blocked, not failed.',
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
otp(context) {
|
|
42
|
+
return {
|
|
43
|
+
needsInput: true,
|
|
44
|
+
kind: 'otp_or_manual_verification',
|
|
45
|
+
question: (context ? `${context} ` : '') +
|
|
46
|
+
'A one-time code / manual verification step is required. Provide the code, or approve manual completion.',
|
|
47
|
+
fields: [{ name: 'otp', secret: true, description: 'One-time code from SMS/email/authenticator' }],
|
|
48
|
+
fallbackOptions: ['complete this step manually, then continue', 'skip flows requiring verification'],
|
|
49
|
+
resume: resumeVia('otp_or_manual_verification'),
|
|
50
|
+
attempted: [],
|
|
51
|
+
ifDeclined: 'Flows behind the verification step are skipped and reported as blocked.',
|
|
52
|
+
};
|
|
53
|
+
},
|
|
54
|
+
monorepoTarget(candidates) {
|
|
55
|
+
return {
|
|
56
|
+
needsInput: true,
|
|
57
|
+
kind: 'monorepo_target',
|
|
58
|
+
question: `This is a monorepo with multiple app targets. Which one should Swipium test?`,
|
|
59
|
+
fields: [{ name: 'target', secret: false, description: 'App package/directory to test', example: candidates[0] }],
|
|
60
|
+
fallbackOptions: candidates.slice(0, 6),
|
|
61
|
+
resume: { tool: 'qa_continue_from_blocker', args: { kind: 'monorepo_target' } },
|
|
62
|
+
attempted: [],
|
|
63
|
+
ifDeclined: 'Swipium cannot guess the intended app; the run does not start until a target is chosen.',
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
preferredPlatform(available) {
|
|
67
|
+
return {
|
|
68
|
+
needsInput: true,
|
|
69
|
+
kind: 'preferred_platform',
|
|
70
|
+
question: `More than one platform is available. Which should Swipium test first?`,
|
|
71
|
+
fields: [{ name: 'platform', secret: false, example: available[0] }],
|
|
72
|
+
fallbackOptions: available,
|
|
73
|
+
resume: resumeVia('preferred_platform'),
|
|
74
|
+
attempted: [],
|
|
75
|
+
ifDeclined: 'Swipium picks the first available platform automatically and records it as a workaround.',
|
|
76
|
+
};
|
|
77
|
+
},
|
|
78
|
+
destructiveExplorationApproval(what) {
|
|
79
|
+
return {
|
|
80
|
+
needsInput: true,
|
|
81
|
+
kind: 'destructive_exploration_approval',
|
|
82
|
+
question: `${what} Exploring it may trigger destructive actions (delete/reset/purchase). Approve, or keep exploration read-only?`,
|
|
83
|
+
fields: [{ name: 'approveDestructive', secret: false, description: 'true to allow potentially destructive exploration' }],
|
|
84
|
+
fallbackOptions: ['keep exploration non-destructive (skip risky controls)', 'approve destructive exploration', 'run destructive steps last'],
|
|
85
|
+
resume: resumeVia('destructive_exploration_approval'),
|
|
86
|
+
attempted: [],
|
|
87
|
+
ifDeclined: 'Swipium explores non-destructively and skips controls flagged as risky.',
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
signingTeam() {
|
|
91
|
+
return {
|
|
92
|
+
needsInput: true,
|
|
93
|
+
kind: 'signing_team',
|
|
94
|
+
question: 'A simulator build needs Xcode signing/build settings. Provide a development team if your project requires one, or adjust the simulator build.',
|
|
95
|
+
fields: [
|
|
96
|
+
{ name: 'developmentTeam', secret: false, description: 'Apple Developer Team ID' },
|
|
97
|
+
{ name: 'provisioningProfile', secret: false, description: 'Provisioning profile name (optional)' },
|
|
98
|
+
],
|
|
99
|
+
fallbackOptions: ['test on simulator instead', 'set up signing in Xcode, then retry'],
|
|
100
|
+
resume: resumeVia('signing_team'),
|
|
101
|
+
attempted: [],
|
|
102
|
+
ifDeclined: 'Swipium reports simulator preparation as blocked until the build settings are fixed.',
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
artifactOutsideRoot(path) {
|
|
106
|
+
return {
|
|
107
|
+
needsInput: true,
|
|
108
|
+
kind: 'artifact_outside_root',
|
|
109
|
+
question: `The best artifact is outside the project root (${path}). Use it anyway?`,
|
|
110
|
+
fields: [{ name: 'allowOutsideRoot', secret: false }],
|
|
111
|
+
fallbackOptions: ['use it (allowOutsideRoot)', 'build inside the project instead', 'pass an explicit path'],
|
|
112
|
+
resume: resumeVia('artifact_outside_root'),
|
|
113
|
+
attempted: [],
|
|
114
|
+
ifDeclined: 'Swipium ignores the outside-root artifact and tries to build inside the project, or blocks if it cannot.',
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
externalServiceRequired(service) {
|
|
118
|
+
return {
|
|
119
|
+
needsInput: true,
|
|
120
|
+
kind: 'external_service_required',
|
|
121
|
+
question: `This run needs an external service: ${service}. Provide access/approval to use it, or choose a fallback.`,
|
|
122
|
+
fields: [
|
|
123
|
+
{ name: 'serviceEndpoint', secret: false, description: 'URL/host of the required service (if applicable)' },
|
|
124
|
+
{ name: 'serviceToken', secret: true, description: 'Access token/key for the service (if required)' },
|
|
125
|
+
],
|
|
126
|
+
fallbackOptions: ['provide service access', 'mock/stub the service', 'skip flows that need it'],
|
|
127
|
+
resume: resumeVia('external_service_required'),
|
|
128
|
+
attempted: [],
|
|
129
|
+
ifDeclined: 'Flows depending on the external service are skipped and reported as blocked.',
|
|
130
|
+
};
|
|
131
|
+
},
|
|
132
|
+
// ---- retained legacy builders (backward compatibility) ----
|
|
133
|
+
destructiveResetApproval(what) {
|
|
134
|
+
return {
|
|
135
|
+
needsInput: true,
|
|
136
|
+
kind: 'destructive_reset_approval',
|
|
137
|
+
question: `${what} This is destructive. Approve it, or choose a non-destructive path.`,
|
|
138
|
+
fields: [{ name: 'approve', secret: false, description: 'true to approve the destructive reset' }],
|
|
139
|
+
fallbackOptions: ['use a release build for clean-state tests', 'run destructive steps last', 'do not reset'],
|
|
140
|
+
resume: resumeVia('destructive_reset_approval'),
|
|
141
|
+
attempted: [],
|
|
142
|
+
ifDeclined: 'Swipium skips the destructive reset and tests from the current app state.',
|
|
143
|
+
};
|
|
144
|
+
},
|
|
145
|
+
createTestData(what) {
|
|
146
|
+
return {
|
|
147
|
+
needsInput: true,
|
|
148
|
+
kind: 'create_test_data',
|
|
149
|
+
question: `${what} Should Swipium create the required account/test data, or will you provide it?`,
|
|
150
|
+
fields: [{ name: 'createTestData', secret: false, description: 'true to let Swipium seed it (consent-gated)' }],
|
|
151
|
+
fallbackOptions: ['provide existing test data', 'skip flows needing this data'],
|
|
152
|
+
resume: resumeVia('create_test_data'),
|
|
153
|
+
attempted: [],
|
|
154
|
+
ifDeclined: 'Flows needing the data are skipped and reported as blocked.',
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
visualOnlyFallback(screen) {
|
|
158
|
+
return {
|
|
159
|
+
needsInput: true,
|
|
160
|
+
kind: 'visual_only_fallback',
|
|
161
|
+
question: `${screen ? `Screen "${screen}" ` : 'This screen '}has no usable UI tree (canvas/map/webview). ` +
|
|
162
|
+
'Use visual-only verification (screenshots), which is weaker evidence?',
|
|
163
|
+
fields: [{ name: 'allowVisualOnly', secret: false }],
|
|
164
|
+
fallbackOptions: ['use visual-only fallback', 'skip this screen', 'add accessibility identifiers and retry'],
|
|
165
|
+
resume: resumeVia('visual_only_fallback'),
|
|
166
|
+
attempted: [],
|
|
167
|
+
ifDeclined: 'Swipium skips the screen and reports it as not verifiable via the UI tree.',
|
|
168
|
+
};
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
function renderQuestion(p) {
|
|
172
|
+
const fields = p.fields.map((f) => `${f.name}${f.secret ? ' (secret)' : ''}`).join(', ');
|
|
173
|
+
return [
|
|
174
|
+
`❓ ${p.question}`,
|
|
175
|
+
fields ? `provide: ${fields}` : '',
|
|
176
|
+
p.fallbackOptions.length ? `or: ${p.fallbackOptions.join(' | ')}` : '',
|
|
177
|
+
p.ifDeclined ? `if declined: ${p.ifDeclined}` : '',
|
|
178
|
+
]
|
|
179
|
+
.filter(Boolean)
|
|
180
|
+
.join('\n');
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Return a NeedsInput result (not an error). The question text is shown in every mode; the
|
|
184
|
+
* full payload is always in structuredContent. `extra` lets a tool attach context (sessionId,
|
|
185
|
+
* what was already tried) the agent needs to resume. When `extra.sessionId` is present it is
|
|
186
|
+
* injected into `resume.args`; `extra.attempted` (string[]) populates `payload.attempted`.
|
|
187
|
+
*/
|
|
188
|
+
export function qaNeedsInput(p, extra) {
|
|
189
|
+
const sessionId = extra?.sessionId;
|
|
190
|
+
const attempted = Array.isArray(extra?.attempted) ? extra.attempted : p.attempted;
|
|
191
|
+
const resume = {
|
|
192
|
+
tool: p.resume.tool,
|
|
193
|
+
args: { ...(typeof sessionId === 'string' ? { sessionId } : {}), ...p.resume.args },
|
|
194
|
+
};
|
|
195
|
+
const enriched = { ...p, attempted, resume };
|
|
196
|
+
const payload = { ok: true, ...enriched, ...(extra ?? {}) };
|
|
197
|
+
const head = renderQuestion(enriched);
|
|
198
|
+
const text = currentResponseMode() === 'compact' ? head : `${head}\n\`\`\`json\n${JSON.stringify(payload, null, 2)}\n\`\`\``;
|
|
199
|
+
return { content: [{ type: 'text', text }], structuredContent: payload };
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=needsInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"needsInput.js","sourceRoot":"","sources":["../../src/lib/needsInput.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/png.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// Minimal zero-dependency PNG decode (PHASE3-PLAN §8). Device screenshots come from
|
|
2
|
+
// `screencap -p` as non-interlaced 8-bit truecolor(+alpha) PNGs, so we support exactly that
|
|
3
|
+
// (color types 2 and 6, bit depth 8, interlace 0) and error clearly on anything else. Uses
|
|
4
|
+
// Node's built-in zlib — no image library, no third-party code.
|
|
5
|
+
import { inflateSync } from 'node:zlib';
|
|
6
|
+
/** Read width/height from the IHDR without decoding pixels (for the coordinate-space audit). */
|
|
7
|
+
export function pngSize(buf) {
|
|
8
|
+
if (buf.length < 24 || buf.readUInt32BE(0) !== 0x89504e47)
|
|
9
|
+
return null; // PNG signature
|
|
10
|
+
// IHDR data starts at byte 16 (after 8-byte sig + 4 len + 4 type)
|
|
11
|
+
return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
|
|
12
|
+
}
|
|
13
|
+
function paeth(a, b, c) {
|
|
14
|
+
const p = a + b - c;
|
|
15
|
+
const pa = Math.abs(p - a);
|
|
16
|
+
const pb = Math.abs(p - b);
|
|
17
|
+
const pc = Math.abs(p - c);
|
|
18
|
+
if (pa <= pb && pa <= pc)
|
|
19
|
+
return a;
|
|
20
|
+
return pb <= pc ? b : c;
|
|
21
|
+
}
|
|
22
|
+
export function decodePng(buf) {
|
|
23
|
+
if (buf.length < 8 || buf.readUInt32BE(0) !== 0x89504e47)
|
|
24
|
+
throw new Error('not a PNG');
|
|
25
|
+
let pos = 8;
|
|
26
|
+
let width = 0;
|
|
27
|
+
let height = 0;
|
|
28
|
+
let bitDepth = 0;
|
|
29
|
+
let colorType = 0;
|
|
30
|
+
let interlace = 0;
|
|
31
|
+
const idat = [];
|
|
32
|
+
while (pos + 8 <= buf.length) {
|
|
33
|
+
const len = buf.readUInt32BE(pos);
|
|
34
|
+
const type = buf.toString('ascii', pos + 4, pos + 8);
|
|
35
|
+
const dataStart = pos + 8;
|
|
36
|
+
if (type === 'IHDR') {
|
|
37
|
+
width = buf.readUInt32BE(dataStart);
|
|
38
|
+
height = buf.readUInt32BE(dataStart + 4);
|
|
39
|
+
bitDepth = buf[dataStart + 8];
|
|
40
|
+
colorType = buf[dataStart + 9];
|
|
41
|
+
interlace = buf[dataStart + 12];
|
|
42
|
+
}
|
|
43
|
+
else if (type === 'IDAT') {
|
|
44
|
+
idat.push(buf.subarray(dataStart, dataStart + len));
|
|
45
|
+
}
|
|
46
|
+
else if (type === 'IEND') {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
pos = dataStart + len + 4; // skip data + CRC
|
|
50
|
+
}
|
|
51
|
+
if (bitDepth !== 8 || interlace !== 0 || (colorType !== 2 && colorType !== 6)) {
|
|
52
|
+
throw new Error(`unsupported PNG (bitDepth=${bitDepth}, colorType=${colorType}, interlace=${interlace}); expected 8-bit truecolor`);
|
|
53
|
+
}
|
|
54
|
+
const channels = colorType === 6 ? 4 : 3;
|
|
55
|
+
const raw = inflateSync(Buffer.concat(idat));
|
|
56
|
+
const stride = width * channels;
|
|
57
|
+
const out = Buffer.allocUnsafe(height * stride);
|
|
58
|
+
// Un-filter each scanline (PNG filter types 0..4), reconstructing in place.
|
|
59
|
+
let rp = 0;
|
|
60
|
+
for (let y = 0; y < height; y++) {
|
|
61
|
+
const filter = raw[rp++];
|
|
62
|
+
const o = y * stride;
|
|
63
|
+
const po = (y - 1) * stride;
|
|
64
|
+
for (let x = 0; x < stride; x++) {
|
|
65
|
+
const cur = raw[rp++];
|
|
66
|
+
const a = x >= channels ? out[o + x - channels] : 0; // left
|
|
67
|
+
const b = y > 0 ? out[po + x] : 0; // up
|
|
68
|
+
const c = x >= channels && y > 0 ? out[po + x - channels] : 0; // up-left
|
|
69
|
+
let val;
|
|
70
|
+
switch (filter) {
|
|
71
|
+
case 0:
|
|
72
|
+
val = cur;
|
|
73
|
+
break;
|
|
74
|
+
case 1:
|
|
75
|
+
val = cur + a;
|
|
76
|
+
break;
|
|
77
|
+
case 2:
|
|
78
|
+
val = cur + b;
|
|
79
|
+
break;
|
|
80
|
+
case 3:
|
|
81
|
+
val = cur + ((a + b) >> 1);
|
|
82
|
+
break;
|
|
83
|
+
case 4:
|
|
84
|
+
val = cur + paeth(a, b, c);
|
|
85
|
+
break;
|
|
86
|
+
default: throw new Error(`bad PNG filter ${filter} at row ${y}`);
|
|
87
|
+
}
|
|
88
|
+
out[o + x] = val & 0xff;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { width, height, channels, data: out };
|
|
92
|
+
}
|
|
93
|
+
/** Convert a decoded image to a grayscale Uint8Array (one byte per pixel). */
|
|
94
|
+
export function toGray(img) {
|
|
95
|
+
const { width, height, channels, data } = img;
|
|
96
|
+
const g = new Uint8Array(width * height);
|
|
97
|
+
for (let i = 0, p = 0; i < g.length; i++, p += channels) {
|
|
98
|
+
// Rec.601 luma
|
|
99
|
+
g[i] = (data[p] * 0.299 + data[p + 1] * 0.587 + data[p + 2] * 0.114) | 0;
|
|
100
|
+
}
|
|
101
|
+
return g;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=png.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"png.js","sourceRoot":"","sources":["../../src/lib/png.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// Sensitive-mode redaction (DESIGN §9.7, M6). Two mechanisms:
|
|
2
|
+
// 1. isSecureNode → a field whose VALUE must never be shown (password/OTP/etc.).
|
|
3
|
+
// 2. makeRedactor → scrub known secret values (things typed into secure fields) from any
|
|
4
|
+
// string we emit (snapshots, inspect, report, dump-xml artifacts, logs).
|
|
5
|
+
const SECRET_RE = /password|passwd|otp|one.?time|pin\b|cvv|card.?number|secret|token|security.?code/i;
|
|
6
|
+
export function isSecureNode(n) {
|
|
7
|
+
return n.attrs?.password === 'true' || SECRET_RE.test(n.id) || SECRET_RE.test(n.desc);
|
|
8
|
+
}
|
|
9
|
+
export function makeRedactor(secrets) {
|
|
10
|
+
const list = [...secrets].filter((x) => x && x.length >= 2).sort((a, b) => b.length - a.length);
|
|
11
|
+
return (s) => {
|
|
12
|
+
if (!s || list.length === 0)
|
|
13
|
+
return s;
|
|
14
|
+
let out = s;
|
|
15
|
+
for (const sec of list)
|
|
16
|
+
if (out.includes(sec))
|
|
17
|
+
out = out.split(sec).join('«redacted»');
|
|
18
|
+
return out;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/lib/redact.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,kFAAkF;AAClF,0FAA0F;AAC1F,6EAA6E;AAI7E,MAAM,SAAS,GAAG,mFAAmF,CAAC;AAEtG,MAAM,UAAU,YAAY,CAAC,CAAyC;IACpE,OAAO,CAAC,CAAC,KAAK,EAAE,QAAQ,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACxF,CAAC;AAID,MAAM,UAAU,YAAY,CAAC,OAAyB;IACpD,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAChG,OAAO,CAAC,CAAU,EAAE,EAAE;QACpB,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QACtC,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,MAAM,GAAG,IAAI,IAAI;YAAE,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACvF,OAAO,GAAG,CAAC;IACb,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Tool result envelopes (DESIGN §3 "Every tool is self-diagnosing", §2.1 contract).
|
|
2
|
+
//
|
|
3
|
+
// Recoverable failures are returned as isError:true with a structured, actionable
|
|
4
|
+
// payload — NOT thrown. Thrown/JSON-RPC errors are reserved for malformed calls or a
|
|
5
|
+
// broken server (the model can't act on those).
|
|
6
|
+
//
|
|
7
|
+
// Response modes (PHASE3-PLAN §2.1): a session can ask for `compact | normal | verbose`
|
|
8
|
+
// output. The human-readable text is rendered per mode; `structuredContent` is ALWAYS the
|
|
9
|
+
// full payload, so a client that reads structured data loses nothing in compact mode. The
|
|
10
|
+
// active mode is carried in AsyncLocalStorage so EVERY tool inherits it without touching a
|
|
11
|
+
// single call site, and concurrent JSON-RPC requests can't clobber each other's mode.
|
|
12
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
13
|
+
export const DEFAULT_RESPONSE_MODE = 'normal';
|
|
14
|
+
const modeStore = new AsyncLocalStorage();
|
|
15
|
+
/** Run `fn` with `mode` as the active response mode for everything it (asynchronously) calls. */
|
|
16
|
+
export function runWithResponseMode(mode, fn) {
|
|
17
|
+
return modeStore.run(mode, fn);
|
|
18
|
+
}
|
|
19
|
+
/** The response mode in effect for the current tool call (default normal). */
|
|
20
|
+
export function currentResponseMode() {
|
|
21
|
+
return modeStore.getStore() ?? DEFAULT_RESPONSE_MODE;
|
|
22
|
+
}
|
|
23
|
+
function fence(obj) {
|
|
24
|
+
return '```json\n' + JSON.stringify(obj, null, 2) + '\n```';
|
|
25
|
+
}
|
|
26
|
+
/** Pull any artifact/resource URIs out of a payload so compact mode can still surface them. */
|
|
27
|
+
function uriLines(payload) {
|
|
28
|
+
const out = [];
|
|
29
|
+
const push = (label, v) => {
|
|
30
|
+
if (typeof v === 'string' && v.startsWith('swipium://'))
|
|
31
|
+
out.push(`${label}: ${v}`);
|
|
32
|
+
};
|
|
33
|
+
push('artifact', payload.artifactUri);
|
|
34
|
+
if (Array.isArray(payload.artifactUris)) {
|
|
35
|
+
for (const u of payload.artifactUris)
|
|
36
|
+
push('artifact', u);
|
|
37
|
+
}
|
|
38
|
+
push('screenshot', payload.screenshotUri);
|
|
39
|
+
push('report', payload.reportUri);
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Compose the human text block for a result. compact = summary (+ any artifact URIs) only,
|
|
44
|
+
* dropping the fenced-JSON duplicate that structuredContent already carries; normal/verbose
|
|
45
|
+
* keep the fence for clients/humans reading the text channel.
|
|
46
|
+
*/
|
|
47
|
+
function renderText(summary, payload, mode) {
|
|
48
|
+
if (mode === 'compact') {
|
|
49
|
+
const uris = uriLines(payload);
|
|
50
|
+
return uris.length ? `${summary}\n${uris.join('\n')}` : summary;
|
|
51
|
+
}
|
|
52
|
+
return `${summary}\n\n${fence(payload)}`;
|
|
53
|
+
}
|
|
54
|
+
export function qaError(p, extra) {
|
|
55
|
+
const payload = { ok: false, ...p, ...(extra ?? {}) };
|
|
56
|
+
const mode = currentResponseMode();
|
|
57
|
+
const head = [
|
|
58
|
+
`❌ ${p.what}`,
|
|
59
|
+
p.commandAttempted ? `command: ${p.commandAttempted}` : '',
|
|
60
|
+
`changedState=${p.changedState} retrySafe=${p.retrySafe}`,
|
|
61
|
+
p.nextSteps.length ? `next: ${p.nextSteps.join(' | ')}` : '',
|
|
62
|
+
p.clientHint ? `hint: ${p.clientHint}` : '',
|
|
63
|
+
]
|
|
64
|
+
.filter(Boolean)
|
|
65
|
+
.join('\n');
|
|
66
|
+
// Errors keep their actionable head in every mode; only the fenced JSON duplicate is
|
|
67
|
+
// dropped in compact (structuredContent still carries the full payload).
|
|
68
|
+
const text = mode === 'compact' ? head : `${head}\n${fence(payload)}`;
|
|
69
|
+
return { isError: true, content: [{ type: 'text', text }], structuredContent: payload };
|
|
70
|
+
}
|
|
71
|
+
export function qaOk(payload, summary) {
|
|
72
|
+
const structured = { ok: true, ...payload };
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: 'text', text: renderText(summary, structured, currentResponseMode()) }],
|
|
75
|
+
structuredContent: structured,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** A deliberate, budgeted stop (not an error). The agent should call qa_report next. */
|
|
79
|
+
export function qaStop(reason, payload) {
|
|
80
|
+
const structured = { ok: true, stopped: true, reason, ...payload };
|
|
81
|
+
const summary = `⏹ Stopped: ${reason}\nCall qa_report to summarize what was verified.`;
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: 'text', text: renderText(summary, structured, currentResponseMode()) }],
|
|
84
|
+
structuredContent: structured,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../../src/lib/result.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Schema-hash freshness (Phase 3.3 Milestone A). A version bump tells a HUMAN the server changed,
|
|
2
|
+
// but a client running a pre-upgrade build with the same tool COUNT can still look fresh after a
|
|
3
|
+
// behavior/schema/description change (the 3.2.1 problem). The schema hash is a content fingerprint
|
|
4
|
+
// of the registered tool surface — names + descriptions + input-parameter keys — so an agent/client
|
|
5
|
+
// can detect "same count, different surface" and know to restart.
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
/** Deterministic hash of the tool surface (order-independent). */
|
|
8
|
+
export function computeSchemaHash(entries) {
|
|
9
|
+
const normalized = entries
|
|
10
|
+
.map((e) => ({ name: e.name, description: e.description, inputKeys: [...e.inputKeys].sort() }))
|
|
11
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
12
|
+
return createHash('sha256').update(JSON.stringify(normalized)).digest('hex').slice(0, 16);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Best-effort normalized descriptor of a single zod input field (Phase 3.3 §5 deeper hash). Encodes
|
|
16
|
+
* the type, enum options, optionality, and array/record element types so a NESTED change (e.g. a new
|
|
17
|
+
* enum value or a string→number switch) shifts the hash even when the field name is unchanged.
|
|
18
|
+
* Falls back to 'field' on any introspection surprise — the hash stays stable, never throws.
|
|
19
|
+
*/
|
|
20
|
+
export function describeZodField(schema, depth = 0) {
|
|
21
|
+
if (depth > 4 || !schema || typeof schema !== 'object')
|
|
22
|
+
return 'field';
|
|
23
|
+
const def = schema._def;
|
|
24
|
+
if (!def)
|
|
25
|
+
return 'field';
|
|
26
|
+
const typeName = String(def.typeName ?? '');
|
|
27
|
+
try {
|
|
28
|
+
switch (typeName) {
|
|
29
|
+
case 'ZodOptional':
|
|
30
|
+
case 'ZodNullable':
|
|
31
|
+
return `${describeZodField(def.innerType, depth + 1)}?`;
|
|
32
|
+
case 'ZodDefault':
|
|
33
|
+
return `${describeZodField(def.innerType, depth + 1)}=def`;
|
|
34
|
+
case 'ZodEnum':
|
|
35
|
+
return `enum(${[...(def.values ?? [])].sort().join('|')})`;
|
|
36
|
+
case 'ZodNativeEnum':
|
|
37
|
+
return `nenum(${Object.values(def.values ?? {}).sort().join('|')})`;
|
|
38
|
+
case 'ZodArray':
|
|
39
|
+
return `array<${describeZodField(def.type, depth + 1)}>`;
|
|
40
|
+
case 'ZodRecord':
|
|
41
|
+
return `record<${describeZodField(def.valueType, depth + 1)}>`;
|
|
42
|
+
case 'ZodUnion':
|
|
43
|
+
return `union(${(def.options ?? []).map((o) => describeZodField(o, depth + 1)).join('|')})`;
|
|
44
|
+
case 'ZodObject': {
|
|
45
|
+
const shape = typeof def.shape === 'function' ? def.shape() : def.shape ?? {};
|
|
46
|
+
return `obj{${Object.keys(shape).sort().join(',')}}`;
|
|
47
|
+
}
|
|
48
|
+
default:
|
|
49
|
+
return typeName.replace(/^Zod/, '').toLowerCase() || 'field';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return 'field';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let _hash;
|
|
57
|
+
/** Set once after the server registers all tools. */
|
|
58
|
+
export function setSchemaHash(hash) {
|
|
59
|
+
_hash = hash;
|
|
60
|
+
}
|
|
61
|
+
/** The current tool-surface hash, or 'unknown' if the server has not been built yet. */
|
|
62
|
+
export function getSchemaHash() {
|
|
63
|
+
return _hash ?? 'unknown';
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=schemaHash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemaHash.js","sourceRoot":"","sources":["../../src/lib/schemaHash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Sensitive-mode refusal (NEXT-PLAN: Security — sensitive-mode session option). A single, honest
|
|
2
|
+
// refusal for any pixel/video/log capture when the session opted into sensitive mode, so a
|
|
3
|
+
// privacy-sensitive project can run Swipium with no screen contents leaving the device.
|
|
4
|
+
import { qaError } from './result.js';
|
|
5
|
+
export function sensitiveRefusal(what) {
|
|
6
|
+
return qaError({
|
|
7
|
+
what: `${what} refused — this session is in sensitive mode (no screenshots/video/logs are captured)`,
|
|
8
|
+
changedState: false,
|
|
9
|
+
retrySafe: false,
|
|
10
|
+
nextSteps: ['Start a non-sensitive session (omit sensitive:true) to capture pixels, or rely on structured snapshot + health, which carry no screen contents.'],
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=sensitive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sensitive.js","sourceRoot":"","sources":["../../src/lib/sensitive.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,2FAA2F;AAC3F,wFAAwF;AAExF,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,OAAO,CAAC;QACb,IAAI,EAAE,GAAG,IAAI,uFAAuF;QACpG,YAAY,EAAE,KAAK;QACnB,SAAS,EAAE,KAAK;QAChB,SAAS,EAAE,CAAC,iJAAiJ,CAAC;KAC/J,CAAC,CAAC;AACL,CAAC"}
|