taphound 0.2.0-dev.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.
Files changed (176) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +200 -0
  3. package/README.zh-CN.md +200 -0
  4. package/assets/brand/taphound-mark.svg +9 -0
  5. package/assets/skills/taphound-ai-journey/GUIDE.md +862 -0
  6. package/assets/skills/taphound-ai-journey/SKILL.md +377 -0
  7. package/assets/skills/taphound-ai-journey/prompts/analyze-project.md +526 -0
  8. package/assets/skills/taphound-ai-journey/prompts/check-completion.md +52 -0
  9. package/assets/skills/taphound-ai-journey/prompts/generate-step.md +109 -0
  10. package/assets/skills/taphound-ai-journey/schemas/observe-output.json +42 -0
  11. package/assets/skills/taphound-ai-journey/schemas/project-context.json +81 -0
  12. package/assets/skills/taphound-ai-journey/schemas/proposed-step-envelope.json +267 -0
  13. package/assets/skills/taphound-ai-journey/templates/project-context.example.json +49 -0
  14. package/dist/adapters/adb/adb-adapter.d.ts +23 -0
  15. package/dist/adapters/adb/adb-adapter.js +218 -0
  16. package/dist/adapters/android-cli/android-cli-adapter.d.ts +11 -0
  17. package/dist/adapters/android-cli/android-cli-adapter.js +64 -0
  18. package/dist/adapters/android-cli/layout-parser.d.ts +3 -0
  19. package/dist/adapters/android-cli/layout-parser.js +174 -0
  20. package/dist/adapters/clock/system-clock.d.ts +5 -0
  21. package/dist/adapters/clock/system-clock.js +13 -0
  22. package/dist/adapters/filesystem/artifact-store.d.ts +4 -0
  23. package/dist/adapters/filesystem/artifact-store.js +73 -0
  24. package/dist/adapters/filesystem/generation-meta-writer.d.ts +16 -0
  25. package/dist/adapters/filesystem/generation-meta-writer.js +34 -0
  26. package/dist/adapters/filesystem/generation-session-store.d.ts +68 -0
  27. package/dist/adapters/filesystem/generation-session-store.js +1603 -0
  28. package/dist/adapters/filesystem/journey-writer.d.ts +16 -0
  29. package/dist/adapters/filesystem/journey-writer.js +34 -0
  30. package/dist/adapters/filesystem/project-bound-file.d.ts +6 -0
  31. package/dist/adapters/filesystem/project-bound-file.js +240 -0
  32. package/dist/adapters/filesystem/project-file-inspector.d.ts +8 -0
  33. package/dist/adapters/filesystem/project-file-inspector.js +198 -0
  34. package/dist/adapters/filesystem/skill-installer.d.ts +10 -0
  35. package/dist/adapters/filesystem/skill-installer.js +39 -0
  36. package/dist/adapters/process/node-process-runner.d.ts +8 -0
  37. package/dist/adapters/process/node-process-runner.js +155 -0
  38. package/dist/adapters/prompt/inquirer-generation-prompt.d.ts +55 -0
  39. package/dist/adapters/prompt/inquirer-generation-prompt.js +213 -0
  40. package/dist/adapters/prompt/inquirer-init-prompt.d.ts +32 -0
  41. package/dist/adapters/prompt/inquirer-init-prompt.js +55 -0
  42. package/dist/adapters/prompt/inquirer-recorder-prompt.d.ts +47 -0
  43. package/dist/adapters/prompt/inquirer-recorder-prompt.js +157 -0
  44. package/dist/application/assertion/expectation-evaluator.d.ts +61 -0
  45. package/dist/application/assertion/expectation-evaluator.js +207 -0
  46. package/dist/application/collector/logcat-collector.d.ts +39 -0
  47. package/dist/application/collector/logcat-collector.js +107 -0
  48. package/dist/application/context/context-validator.d.ts +27 -0
  49. package/dist/application/context/context-validator.js +120 -0
  50. package/dist/application/doctor/doctor-service.d.ts +35 -0
  51. package/dist/application/doctor/doctor-service.js +178 -0
  52. package/dist/application/generation/focused-input.d.ts +2 -0
  53. package/dist/application/generation/focused-input.js +9 -0
  54. package/dist/application/generation/generation-confirmation-service.d.ts +76 -0
  55. package/dist/application/generation/generation-confirmation-service.js +383 -0
  56. package/dist/application/generation/generation-finalizer.d.ts +67 -0
  57. package/dist/application/generation/generation-finalizer.js +646 -0
  58. package/dist/application/generation/generation-publisher.d.ts +46 -0
  59. package/dist/application/generation/generation-publisher.js +178 -0
  60. package/dist/application/generation/generation-starter.d.ts +31 -0
  61. package/dist/application/generation/generation-starter.js +102 -0
  62. package/dist/application/generation/generation-step-executor.d.ts +52 -0
  63. package/dist/application/generation/generation-step-executor.js +668 -0
  64. package/dist/application/generation/proposed-step-validator.d.ts +11 -0
  65. package/dist/application/generation/proposed-step-validator.js +88 -0
  66. package/dist/application/generation/risk-evaluator.d.ts +9 -0
  67. package/dist/application/generation/risk-evaluator.js +14 -0
  68. package/dist/application/generation/runtime-observer.d.ts +39 -0
  69. package/dist/application/generation/runtime-observer.js +157 -0
  70. package/dist/application/init/init-service.d.ts +17 -0
  71. package/dist/application/init/init-service.js +44 -0
  72. package/dist/application/interaction/action-executor.d.ts +25 -0
  73. package/dist/application/interaction/action-executor.js +103 -0
  74. package/dist/application/interaction/fallback-resolver.d.ts +24 -0
  75. package/dist/application/interaction/fallback-resolver.js +48 -0
  76. package/dist/application/interaction/scroll-to-executor.d.ts +40 -0
  77. package/dist/application/interaction/scroll-to-executor.js +191 -0
  78. package/dist/application/locator/locator-resolver.d.ts +20 -0
  79. package/dist/application/locator/locator-resolver.js +89 -0
  80. package/dist/application/project/project-describer.d.ts +14 -0
  81. package/dist/application/project/project-describer.js +8 -0
  82. package/dist/application/recorder/locator-selector.d.ts +10 -0
  83. package/dist/application/recorder/locator-selector.js +80 -0
  84. package/dist/application/recorder/recorder-service.d.ts +41 -0
  85. package/dist/application/recorder/recorder-service.js +331 -0
  86. package/dist/application/report/report-writer.d.ts +10 -0
  87. package/dist/application/report/report-writer.js +39 -0
  88. package/dist/application/runtime/activity-waiter.d.ts +33 -0
  89. package/dist/application/runtime/activity-waiter.js +73 -0
  90. package/dist/application/runtime/launch-failure.d.ts +2 -0
  91. package/dist/application/runtime/launch-failure.js +20 -0
  92. package/dist/application/runtime/process-waiter.d.ts +27 -0
  93. package/dist/application/runtime/process-waiter.js +73 -0
  94. package/dist/application/runtime/step-runner.d.ts +50 -0
  95. package/dist/application/runtime/step-runner.js +429 -0
  96. package/dist/application/runtime/verify-runtime.d.ts +44 -0
  97. package/dist/application/runtime/verify-runtime.js +350 -0
  98. package/dist/application/wait/idle-waiter.d.ts +30 -0
  99. package/dist/application/wait/idle-waiter.js +90 -0
  100. package/dist/cli/commands/context.d.ts +3 -0
  101. package/dist/cli/commands/context.js +94 -0
  102. package/dist/cli/commands/doctor.d.ts +3 -0
  103. package/dist/cli/commands/doctor.js +51 -0
  104. package/dist/cli/commands/generation.d.ts +3 -0
  105. package/dist/cli/commands/generation.js +518 -0
  106. package/dist/cli/commands/init.d.ts +3 -0
  107. package/dist/cli/commands/init.js +104 -0
  108. package/dist/cli/commands/project.d.ts +3 -0
  109. package/dist/cli/commands/project.js +58 -0
  110. package/dist/cli/commands/record.d.ts +3 -0
  111. package/dist/cli/commands/record.js +88 -0
  112. package/dist/cli/commands/verify.d.ts +3 -0
  113. package/dist/cli/commands/verify.js +106 -0
  114. package/dist/cli/dependencies.d.ts +66 -0
  115. package/dist/cli/dependencies.js +204 -0
  116. package/dist/cli/main.d.ts +8 -0
  117. package/dist/cli/main.js +73 -0
  118. package/dist/cli/output.d.ts +16 -0
  119. package/dist/cli/output.js +22 -0
  120. package/dist/cli/program.d.ts +3 -0
  121. package/dist/cli/program.js +43 -0
  122. package/dist/domain/activity.d.ts +7 -0
  123. package/dist/domain/activity.js +65 -0
  124. package/dist/domain/app-process.d.ts +7 -0
  125. package/dist/domain/app-process.js +10 -0
  126. package/dist/domain/config.d.ts +15 -0
  127. package/dist/domain/config.js +17 -0
  128. package/dist/domain/failure.d.ts +4 -0
  129. package/dist/domain/failure.js +43 -0
  130. package/dist/domain/generation.d.ts +912 -0
  131. package/dist/domain/generation.js +342 -0
  132. package/dist/domain/init.d.ts +42 -0
  133. package/dist/domain/init.js +114 -0
  134. package/dist/domain/journey.d.ts +673 -0
  135. package/dist/domain/journey.js +109 -0
  136. package/dist/domain/layout.d.ts +35 -0
  137. package/dist/domain/layout.js +33 -0
  138. package/dist/domain/locator.d.ts +8 -0
  139. package/dist/domain/locator.js +5 -0
  140. package/dist/domain/project-context.d.ts +101 -0
  141. package/dist/domain/project-context.js +64 -0
  142. package/dist/domain/proposed-step.d.ts +341 -0
  143. package/dist/domain/proposed-step.js +87 -0
  144. package/dist/domain/report.d.ts +349 -0
  145. package/dist/domain/report.js +135 -0
  146. package/dist/domain/runtime-snapshot.d.ts +16 -0
  147. package/dist/domain/runtime-snapshot.js +46 -0
  148. package/dist/ports/adb.d.ts +42 -0
  149. package/dist/ports/adb.js +1 -0
  150. package/dist/ports/android-cli.d.ts +21 -0
  151. package/dist/ports/android-cli.js +1 -0
  152. package/dist/ports/artifact-store.d.ts +12 -0
  153. package/dist/ports/artifact-store.js +1 -0
  154. package/dist/ports/clock.d.ts +4 -0
  155. package/dist/ports/clock.js +1 -0
  156. package/dist/ports/generation-meta-writer.d.ts +10 -0
  157. package/dist/ports/generation-meta-writer.js +1 -0
  158. package/dist/ports/generation-prompt.d.ts +19 -0
  159. package/dist/ports/generation-prompt.js +6 -0
  160. package/dist/ports/generation-session-store.d.ts +32 -0
  161. package/dist/ports/generation-session-store.js +26 -0
  162. package/dist/ports/init-prompt.d.ts +8 -0
  163. package/dist/ports/init-prompt.js +6 -0
  164. package/dist/ports/journey-writer.d.ts +10 -0
  165. package/dist/ports/journey-writer.js +1 -0
  166. package/dist/ports/process-runner.d.ts +32 -0
  167. package/dist/ports/process-runner.js +1 -0
  168. package/dist/ports/project-bound-file.d.ts +8 -0
  169. package/dist/ports/project-bound-file.js +1 -0
  170. package/dist/ports/project-file-inspector.d.ts +33 -0
  171. package/dist/ports/project-file-inspector.js +1 -0
  172. package/dist/ports/recorder-prompt.d.ts +29 -0
  173. package/dist/ports/recorder-prompt.js +1 -0
  174. package/dist/ports/skill-installer.d.ts +8 -0
  175. package/dist/ports/skill-installer.js +1 -0
  176. package/package.json +64 -0
@@ -0,0 +1,109 @@
1
+ import { z } from "zod";
2
+ import { LocatorSchema } from "./layout.js";
3
+ const QualifiedActivitySchema = z.string().regex(/^(?:[A-Za-z_$][\w$]*\.)+[A-Za-z_$][\w$]*$/, "Activity checkpoint must be fully qualified");
4
+ export const ActivityCheckpointSchema = z.strictObject({
5
+ before: QualifiedActivitySchema,
6
+ after: QualifiedActivitySchema
7
+ });
8
+ const ActivityExpectSchema = z.strictObject({
9
+ type: z.literal("activity"),
10
+ value: QualifiedActivitySchema,
11
+ timeoutMs: z.number().int().positive()
12
+ });
13
+ const ElementExpectSchema = z.strictObject({
14
+ type: z.literal("element"),
15
+ locator: LocatorSchema,
16
+ timeoutMs: z.number().int().positive()
17
+ });
18
+ const LogcatExpectSchema = z.strictObject({
19
+ type: z.literal("logcat"),
20
+ tag: z.string().min(1),
21
+ level: z.enum(["V", "D", "I", "W", "E", "F", "A"]).optional(),
22
+ pattern: z.string().min(1),
23
+ match: z.enum(["literal", "regex"]).default("literal"),
24
+ timeoutMs: z.number().int().positive()
25
+ }).superRefine((expectation, context) => {
26
+ if (expectation.match === "regex") {
27
+ try {
28
+ new RegExp(expectation.pattern);
29
+ }
30
+ catch {
31
+ context.addIssue({
32
+ code: "custom",
33
+ path: ["pattern"],
34
+ message: "pattern must be a valid regular expression"
35
+ });
36
+ }
37
+ }
38
+ });
39
+ export const ExpectSchema = z.discriminatedUnion("type", [
40
+ ActivityExpectSchema,
41
+ ElementExpectSchema,
42
+ LogcatExpectSchema
43
+ ]);
44
+ const CommonStepShape = {
45
+ activity: ActivityCheckpointSchema,
46
+ expect: ExpectSchema.optional()
47
+ };
48
+ export const AnnotatedLabelFallbackSchema = z.strictObject({
49
+ type: z.literal("annotatedLabel"),
50
+ label: z.string().regex(/^#\d+$/, "Fallback label must use Android CLI #number format")
51
+ });
52
+ const ClickStepSchema = z.strictObject({
53
+ action: z.literal("click"),
54
+ locator: LocatorSchema,
55
+ fallback: AnnotatedLabelFallbackSchema.optional(),
56
+ ...CommonStepShape
57
+ });
58
+ const LongClickStepSchema = z.strictObject({
59
+ action: z.literal("longClick"),
60
+ locator: LocatorSchema,
61
+ durationMs: z.number().int().positive().default(800),
62
+ fallback: AnnotatedLabelFallbackSchema.optional(),
63
+ ...CommonStepShape
64
+ });
65
+ const InputTextStepSchema = z.strictObject({
66
+ action: z.literal("inputText"),
67
+ text: z.string().min(1),
68
+ ...CommonStepShape
69
+ });
70
+ const SwipeStepSchema = z.strictObject({
71
+ action: z.literal("swipe"),
72
+ locator: LocatorSchema,
73
+ direction: z.enum(["up", "down", "left", "right"]),
74
+ distancePercent: z.number().positive().max(1).default(0.6),
75
+ durationMs: z.number().int().positive().default(300),
76
+ ...CommonStepShape
77
+ });
78
+ const ScrollToStepSchema = z.strictObject({
79
+ action: z.literal("scrollTo"),
80
+ locator: LocatorSchema,
81
+ container: LocatorSchema,
82
+ direction: z.enum(["up", "down", "left", "right"]),
83
+ maxSwipes: z.number().int().positive().max(30).default(20),
84
+ distancePercent: z.number().positive().max(1).default(0.6),
85
+ durationMs: z.number().int().positive().default(300),
86
+ ...CommonStepShape
87
+ });
88
+ const BackStepSchema = z.strictObject({
89
+ action: z.literal("back"),
90
+ ...CommonStepShape
91
+ });
92
+ const WaitStepSchema = z.strictObject({
93
+ action: z.literal("wait"),
94
+ ...CommonStepShape
95
+ });
96
+ export const JourneyStepSchema = z.discriminatedUnion("action", [
97
+ ClickStepSchema,
98
+ LongClickStepSchema,
99
+ InputTextStepSchema,
100
+ SwipeStepSchema,
101
+ ScrollToStepSchema,
102
+ BackStepSchema,
103
+ WaitStepSchema
104
+ ]);
105
+ export const JourneySchema = z.strictObject({
106
+ version: z.literal(1),
107
+ name: z.string().trim().min(1),
108
+ steps: z.array(JourneyStepSchema).min(1)
109
+ });
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ export declare const BoundsSchema: z.ZodObject<{
3
+ left: z.ZodNumber;
4
+ top: z.ZodNumber;
5
+ right: z.ZodNumber;
6
+ bottom: z.ZodNumber;
7
+ }, z.core.$strict>;
8
+ export type Bounds = z.infer<typeof BoundsSchema>;
9
+ export declare const LayoutPointSchema: z.ZodObject<{
10
+ x: z.ZodNumber;
11
+ y: z.ZodNumber;
12
+ }, z.core.$strict>;
13
+ export type LayoutPoint = z.infer<typeof LayoutPointSchema>;
14
+ export declare const LocatorSchema: z.ZodObject<{
15
+ resourceId: z.ZodOptional<z.ZodString>;
16
+ text: z.ZodOptional<z.ZodString>;
17
+ contentDescription: z.ZodOptional<z.ZodString>;
18
+ }, z.core.$strict>;
19
+ export type Locator = z.infer<typeof LocatorSchema>;
20
+ export interface LayoutElement {
21
+ id: string;
22
+ resourceId?: string | undefined;
23
+ text?: string | undefined;
24
+ contentDescription?: string | undefined;
25
+ clickable?: boolean | undefined;
26
+ longClickable?: boolean | undefined;
27
+ scrollable?: boolean | undefined;
28
+ focusable?: boolean | undefined;
29
+ focused?: boolean | undefined;
30
+ enabled: boolean;
31
+ center?: LayoutPoint | undefined;
32
+ bounds?: Bounds | undefined;
33
+ children: LayoutElement[];
34
+ }
35
+ export declare const LayoutElementSchema: z.ZodType<LayoutElement>;
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ export const BoundsSchema = z.strictObject({
3
+ left: z.number().int().nonnegative(),
4
+ top: z.number().int().nonnegative(),
5
+ right: z.number().int().positive(),
6
+ bottom: z.number().int().positive()
7
+ }).refine(({ left, right }) => right > left, { message: "right must be greater than left", path: ["right"] }).refine(({ bottom, top }) => bottom > top, { message: "bottom must be greater than top", path: ["bottom"] });
8
+ export const LayoutPointSchema = z.strictObject({
9
+ x: z.number().int().nonnegative(),
10
+ y: z.number().int().nonnegative()
11
+ });
12
+ export const LocatorSchema = z.strictObject({
13
+ resourceId: z.string().trim().min(1).optional(),
14
+ text: z.string().min(1).optional(),
15
+ contentDescription: z.string().min(1).optional()
16
+ }).refine(({ contentDescription, resourceId, text }) => (resourceId !== undefined
17
+ || text !== undefined
18
+ || contentDescription !== undefined), { message: "Locator must contain a supported identity field" });
19
+ export const LayoutElementSchema = z.lazy(() => z.strictObject({
20
+ id: z.string().min(1),
21
+ resourceId: z.string().min(1).optional(),
22
+ text: z.string().optional(),
23
+ contentDescription: z.string().optional(),
24
+ clickable: z.boolean().optional(),
25
+ longClickable: z.boolean().optional(),
26
+ scrollable: z.boolean().optional(),
27
+ focusable: z.boolean().optional(),
28
+ focused: z.boolean().optional(),
29
+ enabled: z.boolean(),
30
+ center: LayoutPointSchema.optional(),
31
+ bounds: BoundsSchema.optional(),
32
+ children: z.array(LayoutElementSchema).default([])
33
+ }).refine(({ bounds, center }) => bounds !== undefined || center !== undefined, { message: "Layout element requires center or bounds" }));
@@ -0,0 +1,8 @@
1
+ import type { LayoutElement } from "./layout.js";
2
+ export declare const LOCATOR_FIELDS: readonly ["resourceId", "text", "contentDescription"];
3
+ export type LocatorField = (typeof LOCATOR_FIELDS)[number];
4
+ export interface LocatedElement {
5
+ element: LayoutElement;
6
+ field: LocatorField;
7
+ value: string;
8
+ }
@@ -0,0 +1,5 @@
1
+ export const LOCATOR_FIELDS = [
2
+ "resourceId",
3
+ "text",
4
+ "contentDescription"
5
+ ];
@@ -0,0 +1,101 @@
1
+ import { z } from "zod";
2
+ export declare const ContextEvidenceConfidenceSchema: z.ZodEnum<{
3
+ unknown: "unknown";
4
+ sourceConfirmed: "sourceConfirmed";
5
+ runtimeConfirmed: "runtimeConfirmed";
6
+ inferred: "inferred";
7
+ }>;
8
+ export type ContextEvidenceConfidence = z.infer<typeof ContextEvidenceConfidenceSchema>;
9
+ export declare const ProjectRelativePathSchema: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
10
+ export declare const ContextManifestSchema: z.ZodObject<{
11
+ version: z.ZodLiteral<1>;
12
+ files: z.ZodArray<z.ZodObject<{
13
+ path: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
14
+ sha256: z.ZodString;
15
+ confidence: z.ZodEnum<{
16
+ unknown: "unknown";
17
+ sourceConfirmed: "sourceConfirmed";
18
+ runtimeConfirmed: "runtimeConfirmed";
19
+ inferred: "inferred";
20
+ }>;
21
+ }, z.core.$strict>>;
22
+ }, z.core.$strict>;
23
+ export declare const InteractionPolicySchema: z.ZodObject<{
24
+ allowedActions: z.ZodArray<z.ZodEnum<{
25
+ swipe: "swipe";
26
+ click: "click";
27
+ longClick: "longClick";
28
+ inputText: "inputText";
29
+ scrollTo: "scrollTo";
30
+ back: "back";
31
+ wait: "wait";
32
+ }>>;
33
+ confirmationRequiredActions: z.ZodArray<z.ZodEnum<{
34
+ swipe: "swipe";
35
+ click: "click";
36
+ longClick: "longClick";
37
+ inputText: "inputText";
38
+ scrollTo: "scrollTo";
39
+ back: "back";
40
+ wait: "wait";
41
+ }>>;
42
+ forbiddenActions: z.ZodArray<z.ZodEnum<{
43
+ swipe: "swipe";
44
+ click: "click";
45
+ longClick: "longClick";
46
+ inputText: "inputText";
47
+ scrollTo: "scrollTo";
48
+ back: "back";
49
+ wait: "wait";
50
+ }>>;
51
+ }, z.core.$strict>;
52
+ export declare const ProjectContextSchema: z.ZodObject<{
53
+ version: z.ZodLiteral<1>;
54
+ packageName: z.ZodString;
55
+ launchActivity: z.ZodString;
56
+ manifest: z.ZodObject<{
57
+ version: z.ZodLiteral<1>;
58
+ files: z.ZodArray<z.ZodObject<{
59
+ path: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
60
+ sha256: z.ZodString;
61
+ confidence: z.ZodEnum<{
62
+ unknown: "unknown";
63
+ sourceConfirmed: "sourceConfirmed";
64
+ runtimeConfirmed: "runtimeConfirmed";
65
+ inferred: "inferred";
66
+ }>;
67
+ }, z.core.$strict>>;
68
+ }, z.core.$strict>;
69
+ interactionPolicy: z.ZodObject<{
70
+ allowedActions: z.ZodArray<z.ZodEnum<{
71
+ swipe: "swipe";
72
+ click: "click";
73
+ longClick: "longClick";
74
+ inputText: "inputText";
75
+ scrollTo: "scrollTo";
76
+ back: "back";
77
+ wait: "wait";
78
+ }>>;
79
+ confirmationRequiredActions: z.ZodArray<z.ZodEnum<{
80
+ swipe: "swipe";
81
+ click: "click";
82
+ longClick: "longClick";
83
+ inputText: "inputText";
84
+ scrollTo: "scrollTo";
85
+ back: "back";
86
+ wait: "wait";
87
+ }>>;
88
+ forbiddenActions: z.ZodArray<z.ZodEnum<{
89
+ swipe: "swipe";
90
+ click: "click";
91
+ longClick: "longClick";
92
+ inputText: "inputText";
93
+ scrollTo: "scrollTo";
94
+ back: "back";
95
+ wait: "wait";
96
+ }>>;
97
+ }, z.core.$strict>;
98
+ }, z.core.$strict>;
99
+ export type ContextManifest = z.infer<typeof ContextManifestSchema>;
100
+ export type InteractionPolicy = z.infer<typeof InteractionPolicySchema>;
101
+ export type ProjectContext = z.infer<typeof ProjectContextSchema>;
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ const QualifiedNameSchema = z.string().regex(/^(?:[A-Za-z_$][\w$]*\.)+[A-Za-z_$][\w$]*$/, "Value must be fully qualified");
3
+ const GenerationActionSchema = z.enum([
4
+ "click",
5
+ "longClick",
6
+ "inputText",
7
+ "swipe",
8
+ "scrollTo",
9
+ "back",
10
+ "wait"
11
+ ]);
12
+ export const ContextEvidenceConfidenceSchema = z.enum([
13
+ "sourceConfirmed",
14
+ "runtimeConfirmed",
15
+ "inferred",
16
+ "unknown"
17
+ ]);
18
+ export const ProjectRelativePathSchema = z.string()
19
+ .trim()
20
+ .min(1)
21
+ .transform((path) => path.replaceAll("\\", "/"))
22
+ .refine((path) => (!path.startsWith("/")
23
+ && !/^[A-Za-z]:/.test(path)
24
+ && !path.split("/").includes("..")), "Path must stay within the project");
25
+ const ContextFileSchema = z.strictObject({
26
+ path: ProjectRelativePathSchema,
27
+ sha256: z.string().regex(/^[a-f\d]{64}$/),
28
+ confidence: ContextEvidenceConfidenceSchema
29
+ });
30
+ export const ContextManifestSchema = z.strictObject({
31
+ version: z.literal(1),
32
+ files: z.array(ContextFileSchema).min(1)
33
+ });
34
+ export const InteractionPolicySchema = z.strictObject({
35
+ allowedActions: z.array(GenerationActionSchema),
36
+ confirmationRequiredActions: z.array(GenerationActionSchema),
37
+ forbiddenActions: z.array(GenerationActionSchema)
38
+ }).superRefine((policy, context) => {
39
+ const forbidden = new Set(policy.forbiddenActions);
40
+ const overlap = policy.allowedActions.find((action) => forbidden.has(action));
41
+ if (overlap !== undefined) {
42
+ context.addIssue({
43
+ code: "custom",
44
+ path: ["forbiddenActions"],
45
+ message: `${overlap} cannot be both allowed and forbidden`
46
+ });
47
+ }
48
+ const allowed = new Set(policy.allowedActions);
49
+ const invalidConfirmation = policy.confirmationRequiredActions.find((action) => !allowed.has(action));
50
+ if (invalidConfirmation !== undefined) {
51
+ context.addIssue({
52
+ code: "custom",
53
+ path: ["confirmationRequiredActions"],
54
+ message: `${invalidConfirmation} must be allowed before requiring confirmation`
55
+ });
56
+ }
57
+ });
58
+ export const ProjectContextSchema = z.strictObject({
59
+ version: z.literal(1),
60
+ packageName: QualifiedNameSchema,
61
+ launchActivity: QualifiedNameSchema,
62
+ manifest: ContextManifestSchema,
63
+ interactionPolicy: InteractionPolicySchema
64
+ });