testeiya 0.4.4 → 0.4.6
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/README.md +21 -1
- package/dist/prompt/clis.js +38 -0
- package/dist/prompt/clis.js.map +1 -0
- package/dist/prompt/report.js +38 -0
- package/dist/prompt/report.js.map +1 -0
- package/dist/prompt/system-prompt.js +77 -174
- package/dist/prompt/system-prompt.js.map +1 -1
- package/dist/prompt/testomat.io.js +47 -0
- package/dist/prompt/testomat.io.js.map +1 -0
- package/dist/prompt/thread.js +161 -0
- package/dist/prompt/thread.js.map +1 -0
- package/dist/src/doctor.js +9 -1
- package/dist/src/doctor.js.map +1 -1
- package/dist/src/langfuse-extension.js +135 -0
- package/dist/src/langfuse-extension.js.map +1 -0
- package/dist/src/langfuse.js +143 -0
- package/dist/src/langfuse.js.map +1 -0
- package/dist/src/output.js +48 -3
- package/dist/src/output.js.map +1 -1
- package/dist/src/run.js +51 -13
- package/dist/src/run.js.map +1 -1
- package/dist/src/session.js +23 -8
- package/dist/src/session.js.map +1 -1
- package/package.json +1 -1
- package/prompt/clis.ts +45 -0
- package/prompt/report.ts +46 -0
- package/prompt/system-prompt.ts +89 -184
- package/prompt/testomat.io.ts +63 -0
- package/prompt/thread.ts +208 -0
- package/skills/playwright/playwright-cli/SKILL.md +49 -0
- package/skills/playwright/playwright-cli/references/pr-attachments.md +60 -0
- package/skills/playwright/playwright-cli/references/session-management.md +2 -0
- package/skills/playwright/playwright-cli/references/video-recording.md +12 -0
- package/skills/skills.lock.json +2 -2
- package/skills/testomatio/requirements/write-user-story/SKILL.md +7 -10
- package/skills/testomatio/test-management/scan-automation-project/SKILL.md +103 -26
- package/dist/prompt/comment-thread.js +0 -96
- package/dist/prompt/comment-thread.js.map +0 -1
- package/dist/prompt/context.js +0 -87
- package/dist/prompt/context.js.map +0 -1
- package/dist/prompt/index.js +0 -60
- package/dist/prompt/index.js.map +0 -1
- package/dist/prompt/print.js +0 -30
- package/dist/prompt/print.js.map +0 -1
- package/dist/prompt/project-info.js +0 -2
- package/dist/prompt/project-info.js.map +0 -1
- package/dist/prompt/testomatio.js +0 -264
- package/dist/prompt/testomatio.js.map +0 -1
- package/dist/prompt/tools.js +0 -70
- package/dist/prompt/tools.js.map +0 -1
- package/dist/prompt/vocab.js +0 -8
- package/dist/prompt/vocab.js.map +0 -1
- package/prompt/comment-thread.ts +0 -126
- package/prompt/context.ts +0 -108
- package/prompt/index.ts +0 -102
- package/prompt/print.ts +0 -32
- package/prompt/project-info.ts +0 -30
- package/prompt/testomatio.ts +0 -281
- package/prompt/tools.ts +0 -72
- package/prompt/vocab.ts +0 -7
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
import dedent from "dedent";
|
|
2
|
-
const MAX_PROMPT_LABELS = 20;
|
|
3
|
-
const MAX_PROMPT_TAGS = 30;
|
|
4
|
-
const MAX_PROMPT_ENVS = 15;
|
|
5
|
-
const tmsViaDirectTools = dedent `
|
|
6
|
-
# Testomat.io-first operating rules (highest priority)
|
|
7
|
-
|
|
8
|
-
This agent works on Testomat.io projects. You have TWO sources of truth and they answer different kinds of questions:
|
|
9
|
-
|
|
10
|
-
1. **The pulled markdown workspace (\`cwd\`)** — for **tests** and **suites**. Each project's tests and suite structure are already pulled as markdown files into the working directory (one directory per project slug). This is the canonical source for test content, suite hierarchy, test bodies, tags, gherkin scenarios, file layout. Use \`read\`, \`find\`, \`grep\`, \`ls\` — they're instant and don't hit the network.
|
|
11
|
-
2. **MCP tools under \`testomatio-<slug>\`** — for **dynamic Testomat.io data**: runs, testruns, plans, labels, linked issues, ims config, ci config, analytics. These things don't live as files and MUST come from MCP.
|
|
12
|
-
|
|
13
|
-
**Prefer the filesystem for test/suite queries.** Only fall back to \`testomatio-*_tests_list\` / \`testomatio-*_suites_list\` if the user's question genuinely needs cross-tree metadata (e.g. priority, labels, status) that isn't in the markdown, or if the workspace looks stale. Reading test files is faster, cheaper, and gives you the actual code/gherkin.
|
|
14
|
-
|
|
15
|
-
**Never** ask the user for the **Testomat.io** API token — it's configured. (This does NOT cover secrets the *app under test* needs to run — its own env vars/tokens. If a test run is blocked by one of those, ask for it.)
|
|
16
|
-
|
|
17
|
-
**Statuses and counts are live** — runs change them at any time. Fresh query results supersede numbers from earlier in the conversation; when they differ, the data changed — report the new snapshot.
|
|
18
|
-
|
|
19
|
-
## Banned moves
|
|
20
|
-
|
|
21
|
-
- Do NOT call an MCP \`*_tests_list\` or \`*_suites_list\` as your first action for a test/suite question — **read the filesystem first** (\`find\`, \`ls\`, \`grep\`, \`read\`). Fall back to MCP only if the metadata you need isn't in the markdown.
|
|
22
|
-
- Do NOT ask the user for the **Testomat.io** API token — it's already configured. (Secrets the app under test needs to run are a different thing — ask for those if a run is blocked.)
|
|
23
|
-
- Do NOT call \`bash\` / \`find\` / \`grep\` to answer questions about **runs, testruns, plans, labels, linked issues, analytics** — those don't exist as files. Use MCP.
|
|
24
|
-
|
|
25
|
-
## Filesystem vs. MCP cheat sheet
|
|
26
|
-
|
|
27
|
-
| Question is about… | First action |
|
|
28
|
-
|---|---|
|
|
29
|
-
| Test content (code, steps, gherkin, description, file path, tags) | \`read\` / \`find\` / \`grep\` in \`cwd\` |
|
|
30
|
-
| Suite hierarchy / structure / which files exist | \`ls\` / \`find\` |
|
|
31
|
-
| Individual test metadata (priority, status flag, labels) | try filesystem; if missing, \`testomatio-*_tests_get\` |
|
|
32
|
-
| Runs, testruns, plans, labels, issues, analytics | MCP \`testomatio-*\` tools |
|
|
33
|
-
| Creating/updating tests or suites | edit the markdown file, then \`npx check-tests push\` |
|
|
34
|
-
| Creating/updating runs, linking issues | MCP create/update tools |
|
|
35
|
-
| Launching automated or mixed Run remotely on CI | Use npx -y @testomatio/reporter@latest run --remote <profile>, raise error if no CI profiles configured
|
|
36
|
-
| Running automated Run | Use local test runner with testomatio reporter attached to report to current project
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
`;
|
|
40
|
-
const tmsViaProxy = dedent `
|
|
41
|
-
# Testomat.io-first operating rules (highest priority)
|
|
42
|
-
|
|
43
|
-
This agent works on a Testomat.io project. You have TWO sources of truth and they answer different kinds of questions:
|
|
44
|
-
|
|
45
|
-
1. **The pulled markdown workspace (\`cwd\`)** — for **tests** and **suites**. Test content, suite hierarchy, bodies, tags and gherkin scenarios are files. Use \`read\`, \`find\`, \`grep\`, \`ls\` — they are instant and hit no network.
|
|
46
|
-
2. **The \`mcp\` tool** — for **dynamic Testomat.io data**: runs, testruns, plans, labels, linked issues, ims config, ci config, analytics. These do not live as files and MUST come from there.
|
|
47
|
-
|
|
48
|
-
Testomat.io is reached through **one \`mcp\` tool**, not a tool per operation. Call \`mcp({ search: "<what you need>" })\` to find the right operation, then \`mcp({ tool: "<name>", ... })\` to run it. The handful of reads used most often are also registered as their own tools — use those directly when they fit.
|
|
49
|
-
|
|
50
|
-
**Prefer the filesystem for test/suite queries.** Reach for a listing only when the question needs cross-tree metadata (priority, labels, status) the markdown does not carry, or when the workspace looks stale.
|
|
51
|
-
|
|
52
|
-
**Never** ask the user for the **Testomat.io** API token — it's configured. (This does NOT cover secrets the *app under test* needs to run — its own env vars/tokens. If a test run is blocked by one of those, report it.)
|
|
53
|
-
|
|
54
|
-
**Statuses and counts are live** — runs change them at any time. Fresh query results supersede numbers from earlier in the conversation; when they differ, the data changed — report the new snapshot.
|
|
55
|
-
|
|
56
|
-
## Banned moves
|
|
57
|
-
|
|
58
|
-
- Do NOT search for an operation as your first action for a test/suite question — **read the filesystem first** (\`find\`, \`ls\`, \`grep\`, \`read\`). Fall back to a listing only if the metadata you need isn't in the markdown.
|
|
59
|
-
- Do NOT ask the user for the **Testomat.io** API token — it's already configured. (Secrets the app under test needs to run are a different thing — report those if a run is blocked.)
|
|
60
|
-
- Do NOT call \`bash\` / \`find\` / \`grep\` to answer questions about **runs, testruns, plans, labels, linked issues, analytics** — those don't exist as files.
|
|
61
|
-
|
|
62
|
-
## Filesystem vs. Testomat.io cheat sheet
|
|
63
|
-
|
|
64
|
-
| Question is about… | First action |
|
|
65
|
-
|---|---|
|
|
66
|
-
| Test content (code, steps, gherkin, description, file path, tags) | \`read\` / \`find\` / \`grep\` in \`cwd\` |
|
|
67
|
-
| Suite hierarchy / structure / which files exist | \`ls\` / \`find\` |
|
|
68
|
-
| Individual test metadata (priority, status flag, labels) | try filesystem; if missing, \`mcp({ search: "get test" })\` |
|
|
69
|
-
| Runs, testruns, plans, labels, issues, analytics | \`mcp({ search: … })\`, then \`mcp({ tool: … })\` |
|
|
70
|
-
| Creating/updating tests or suites | edit the markdown file, then \`npx check-tests push\` |
|
|
71
|
-
| Creating/updating runs, linking issues | the matching \`mcp\` create/update operation |
|
|
72
|
-
| Launching automated or mixed Run remotely on CI | Use npx -y @testomatio/reporter@latest run --remote <profile>, raise error if no CI profiles configured |
|
|
73
|
-
| Running automated Run | Use local test runner with testomatio reporter attached to report to current project |
|
|
74
|
-
|
|
75
|
-
---
|
|
76
|
-
`;
|
|
77
|
-
const tmsViaCli = dedent `
|
|
78
|
-
# Testomat.io-first operating rules (highest priority)
|
|
79
|
-
|
|
80
|
-
This agent works on a Testomat.io project through the **shell only** — there are no Testomat.io tools in this session.
|
|
81
|
-
|
|
82
|
-
1. **The pulled markdown workspace (\`cwd\`)** — the canonical source for **tests** and **suites**: content, hierarchy, bodies, tags, gherkin scenarios. Use \`read\`, \`find\`, \`grep\`, \`ls\`.
|
|
83
|
-
2. **\`npx check-tests\`** — moves test cases between the markdown and Testomat.io (\`pull\`, \`push\`). It reads its credentials from the environment.
|
|
84
|
-
3. **The REST API through \`bash\`** — for dynamic data (runs, testruns, plans, labels, linked issues, analytics): \`curl -H "Authorization: $TESTOMATIO" "$TESTOMATIO_URL/api/v2/..."\`.
|
|
85
|
-
|
|
86
|
-
**Never** ask the user for the **Testomat.io** API token — it's configured as \`TESTOMATIO\`. (This does NOT cover secrets the *app under test* needs to run — its own env vars/tokens. If a test run is blocked by one of those, report it.)
|
|
87
|
-
|
|
88
|
-
**Statuses and counts are live** — runs change them at any time. Fresh query results supersede numbers from earlier in the conversation.
|
|
89
|
-
|
|
90
|
-
## Banned moves
|
|
91
|
-
|
|
92
|
-
- Do NOT shell out for test content that is already a file in \`cwd\` — read the file.
|
|
93
|
-
- Do NOT invent REST paths or parameters. Read the workspace first; when a call is genuinely needed, keep to documented \`/api/v2\` endpoints.
|
|
94
|
-
- Do NOT ask the user for the **Testomat.io** API token.
|
|
95
|
-
|
|
96
|
-
## Filesystem vs. shell cheat sheet
|
|
97
|
-
|
|
98
|
-
| Question is about… | First action |
|
|
99
|
-
|---|---|
|
|
100
|
-
| Test content (code, steps, gherkin, description, file path, tags) | \`read\` / \`find\` / \`grep\` in \`cwd\` |
|
|
101
|
-
| Suite hierarchy / structure / which files exist | \`ls\` / \`find\` |
|
|
102
|
-
| Runs, testruns, plans, labels, issues, analytics | \`curl\` against \`/api/v2\` |
|
|
103
|
-
| Creating/updating tests or suites | edit the markdown file, then \`npx check-tests push\` |
|
|
104
|
-
| Launching automated or mixed Run remotely on CI | Use npx -y @testomatio/reporter@latest run --remote <profile>, raise error if no CI profiles configured |
|
|
105
|
-
| Running automated Run | Use local test runner with testomatio reporter attached to report to current project |
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
`;
|
|
109
|
-
/**
|
|
110
|
-
* How the agent reaches Testomat.io in this session. The rules are the same;
|
|
111
|
-
* the way to act on them is not, so the harness picks the matching wording.
|
|
112
|
-
*/
|
|
113
|
-
export function testomatioTms(access) {
|
|
114
|
-
if (access === "mcp-proxy")
|
|
115
|
-
return tmsViaProxy;
|
|
116
|
-
if (access === "cli-only")
|
|
117
|
-
return tmsViaCli;
|
|
118
|
-
return tmsViaDirectTools;
|
|
119
|
-
}
|
|
120
|
-
export function testomatioConnection(tokenSlugs, backendUrl, connection, access = "mcp-direct") {
|
|
121
|
-
let urlSuffix = "";
|
|
122
|
-
if (backendUrl)
|
|
123
|
-
urlSuffix = ` (\`${backendUrl}\`)`;
|
|
124
|
-
if (tokenSlugs.length === 0) {
|
|
125
|
-
let project = "";
|
|
126
|
-
if (connection?.projectId)
|
|
127
|
-
project = ` \`${connection.projectId}\``;
|
|
128
|
-
if (connection?.title)
|
|
129
|
-
project += ` ("${connection.title}")`;
|
|
130
|
-
return dedent `
|
|
131
|
-
## Testomat.io Connection (pre-configured)
|
|
132
|
-
|
|
133
|
-
This workspace is linked to the Testomat.io project${project}.
|
|
134
|
-
|
|
135
|
-
The project API key is **already set** as \`TESTOMATIO\` in the environment of every \`bash\` command you run, along with \`TESTOMATIO_URL\`${urlSuffix}. **Never ask the user for a Testomat.io token or API key** — it is already in scope.
|
|
136
|
-
|
|
137
|
-
Push or pull manual test cases with \`npx check-tests\` (or other \`npx @testomatio/*\` commands) — they pick the credentials up from the environment. ${envTokenActions(access)}
|
|
138
|
-
|
|
139
|
-
`;
|
|
140
|
-
}
|
|
141
|
-
if (tokenSlugs.length > 1) {
|
|
142
|
-
const projects = tokenSlugs.map((s) => `- ${s}`).join("\n");
|
|
143
|
-
return dedent `
|
|
144
|
-
## Testomat.io Connection (pre-configured)
|
|
145
|
-
|
|
146
|
-
This session spans several Testomat.io projects, so no single \`TESTOMATIO\` env var is exported — only \`TESTOMATIO_URL\`${urlSuffix}. Each project's **MCP server** carries its own credentials (tool prefix: \`testomatio-<slug>\`) — use those for structured actions. **Never ask the user for a Testomat.io token or API key.** Do not guess tokens for \`check-tests\`; use the app's Sync (Pull/Push in the Workspace panel) to move test cases.
|
|
147
|
-
|
|
148
|
-
Projects pulled into this working directory (one dir per project):
|
|
149
|
-
${projects}
|
|
150
|
-
|
|
151
|
-
`;
|
|
152
|
-
}
|
|
153
|
-
const projects = tokenSlugs.map((s) => `- ${s}`).join("\n");
|
|
154
|
-
return dedent `
|
|
155
|
-
## Testomat.io Connection (pre-configured)
|
|
156
|
-
|
|
157
|
-
The Testomat.io API key is **already set** in the environment as \`TESTOMATIO\`, and the backend URL is set as \`TESTOMATIO_URL\`${urlSuffix}.
|
|
158
|
-
|
|
159
|
-
**Do not ask the user for a Testomat.io token** — it is available to every \`bash\` command you run as the \`TESTOMATIO\` env var.
|
|
160
|
-
|
|
161
|
-
Projects pulled into this working directory (one dir per project):
|
|
162
|
-
${projects}
|
|
163
|
-
|
|
164
|
-
${perProjectActions(access)}
|
|
165
|
-
|
|
166
|
-
When you need to push changes back, run \`npx check-tests push\` (or similar \`npx @testomatio/*\` commands) directly — credentials are already in scope.
|
|
167
|
-
|
|
168
|
-
`;
|
|
169
|
-
}
|
|
170
|
-
export function testomatioNotConnected() {
|
|
171
|
-
return dedent `
|
|
172
|
-
## Testomat.io Connection (not connected)
|
|
173
|
-
|
|
174
|
-
This workspace is not linked to a Testomat.io project and no API key is available in the environment.
|
|
175
|
-
|
|
176
|
-
**Never ask the user to paste a Testomat.io API key or token into the chat.** If a task needs Testomat.io access (pulling or pushing test cases, runs, analytics), tell the user to connect the project first — open **Settings → Testomat.io connection** and link this workspace — then continue once connected. Parts of the task that only touch local files can proceed right away.
|
|
177
|
-
`;
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Compact project-settings block for the system prompt, built from the cached
|
|
181
|
-
* `GET /api/v2/{id}/info` payload (`.testeiya/project-info.json`). Only present
|
|
182
|
-
* fields are rendered; labels/tags are capped with a pointer to the full file.
|
|
183
|
-
*/
|
|
184
|
-
export function projectSettings(info) {
|
|
185
|
-
let heading = `**${info.title}** (\`${info.project_id}\`)`;
|
|
186
|
-
if (info.subscription)
|
|
187
|
-
heading += ` — ${info.subscription} plan`;
|
|
188
|
-
const lines = [];
|
|
189
|
-
const stack = [];
|
|
190
|
-
if (info.framework)
|
|
191
|
-
stack.push(`framework: ${info.framework}`);
|
|
192
|
-
if (info.language)
|
|
193
|
-
stack.push(`language: ${info.language}`);
|
|
194
|
-
if (stack.length > 0)
|
|
195
|
-
lines.push(`- Test stack — ${stack.join(", ")}`);
|
|
196
|
-
if (info.repository_url)
|
|
197
|
-
lines.push(`- Repository: ${info.repository_url}`);
|
|
198
|
-
if (info.artifacts_storage_enabled) {
|
|
199
|
-
lines.push("- Artifacts storage is enabled (test runs can attach screenshots/videos/logs)");
|
|
200
|
-
}
|
|
201
|
-
if (info.environments?.length > 0) {
|
|
202
|
-
const shown = info.environments.slice(0, MAX_PROMPT_ENVS);
|
|
203
|
-
lines.push(`- Environments: ${capped(shown, info.environments.length)}`);
|
|
204
|
-
}
|
|
205
|
-
if (info.features?.length > 0) {
|
|
206
|
-
lines.push(`- Enabled features: ${info.features.join(", ")}`);
|
|
207
|
-
}
|
|
208
|
-
if (info.labels?.length > 0) {
|
|
209
|
-
const shown = info.labels
|
|
210
|
-
.slice(0, MAX_PROMPT_LABELS)
|
|
211
|
-
.map((l) => `${l.title} (\`${l.slug}\`)`);
|
|
212
|
-
lines.push(`- Labels defined in this project: ${capped(shown, info.labels.length)}`);
|
|
213
|
-
}
|
|
214
|
-
if (info.tags?.length > 0) {
|
|
215
|
-
const shown = info.tags.slice(0, MAX_PROMPT_TAGS).map((t) => `@${t}`);
|
|
216
|
-
lines.push(`- Tags in use: ${capped(shown, info.tags.length)}`);
|
|
217
|
-
}
|
|
218
|
-
if (info.ci_profiles?.length > 0) {
|
|
219
|
-
const profiles = info.ci_profiles.map((p) => {
|
|
220
|
-
if (p.service)
|
|
221
|
-
return `"${p.profile_name}" (${p.service})`;
|
|
222
|
-
return `"${p.profile_name}"`;
|
|
223
|
-
});
|
|
224
|
-
lines.push(`- CI profiles configured (runs can be triggered through them): ${profiles.join(", ")}`);
|
|
225
|
-
}
|
|
226
|
-
let body = heading;
|
|
227
|
-
if (lines.length > 0)
|
|
228
|
-
body += `\n\n${lines.join("\n")}`;
|
|
229
|
-
return dedent `
|
|
230
|
-
## Project Settings (Testomat.io)
|
|
231
|
-
|
|
232
|
-
${body}
|
|
233
|
-
|
|
234
|
-
Use these when creating or editing tests: assign only labels that exist here, reuse the existing tags/environments before inventing new ones, and match the project's framework/language when generating automated tests. The full configuration JSON (every label, tag, and CI profile config) is cached at \`.testeiya/project-info.json\` — read that file when you need the complete lists.
|
|
235
|
-
`;
|
|
236
|
-
}
|
|
237
|
-
// How to act on a connection whose token comes from the environment.
|
|
238
|
-
function envTokenActions(access) {
|
|
239
|
-
if (access === "mcp-proxy") {
|
|
240
|
-
return "For structured actions (list/create/update tests, runs, labels, suites, etc.) prefer the `mcp` tool: `mcp({ search })` to find an operation, `mcp({ tool })` to run it.";
|
|
241
|
-
}
|
|
242
|
-
if (access === "cli-only") {
|
|
243
|
-
return "For runs, plans, labels and analytics use `curl` against `/api/v2` — there are no Testomat.io tools in this session.";
|
|
244
|
-
}
|
|
245
|
-
return "If `testomatio-*` MCP tools are available, prefer them for structured actions (list/create/update tests, runs, labels, suites, etc.).";
|
|
246
|
-
}
|
|
247
|
-
// The same, where the harness runs one MCP server per pulled project.
|
|
248
|
-
function perProjectActions(access) {
|
|
249
|
-
if (access === "mcp-proxy") {
|
|
250
|
-
return "The **Testomat.io MCP server** is also connected, reached through the `mcp` tool (`mcp({ search })` to find an operation, `mcp({ tool })` to run it). Prefer it for structured actions (list/create/update tests, runs, labels, suites, etc.) — those are typed, safer, and faster than shell calls. Fall back to `bash` + `check-tests` only for things it does not cover (e.g. pulling full markdown files).";
|
|
251
|
-
}
|
|
252
|
-
if (access === "cli-only") {
|
|
253
|
-
return "There are no Testomat.io tools in this session: use `npx check-tests` for test cases and `curl` against `/api/v2` for runs, plans and labels.";
|
|
254
|
-
}
|
|
255
|
-
return "The **Testomat.io MCP server** is also auto-connected, one instance per project (tool prefix: `testomatio-<slug>`). Prefer MCP tools for structured actions (list/create/update tests, runs, labels, suites, etc.) — they are typed, safer, and faster than shell calls. Fall back to `bash` + `check-tests` only for things the MCP does not cover (e.g. pulling full markdown files).";
|
|
256
|
-
}
|
|
257
|
-
function capped(shown, total) {
|
|
258
|
-
let suffix = "";
|
|
259
|
-
if (total > shown.length) {
|
|
260
|
-
suffix = ` … and ${total - shown.length} more (see \`.testeiya/project-info.json\`)`;
|
|
261
|
-
}
|
|
262
|
-
return shown.join(", ") + suffix;
|
|
263
|
-
}
|
|
264
|
-
//# sourceMappingURL=testomatio.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"testomatio.js","sourceRoot":"","sources":["../../prompt/testomatio.ts"],"names":[],"mappings":"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"}
|
package/dist/prompt/tools.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { delimiter, join } from 'node:path';
|
|
3
|
-
import dedent from 'dedent';
|
|
4
|
-
/**
|
|
5
|
-
* The tools every harness gives the agent. Anything a particular harness adds —
|
|
6
|
-
* a question tool, a browser it can drive for a watching user — arrives as an
|
|
7
|
-
* extra bullet from that harness, since the agent must not be told about a tool
|
|
8
|
-
* it does not have.
|
|
9
|
-
*/
|
|
10
|
-
export function tools(options) {
|
|
11
|
-
const extra = (options?.extra ?? []).join('');
|
|
12
|
-
let routing = ' - GitHub: issues and projects through MCP.';
|
|
13
|
-
if (onPath('gh')) {
|
|
14
|
-
routing +=
|
|
15
|
-
'\n - Pull requests and repositories: `gh` in `bash`. When a PR question needs issue detail, query the issue through MCP — never infer it from a PR title.';
|
|
16
|
-
}
|
|
17
|
-
if (onPath('acli')) {
|
|
18
|
-
routing +=
|
|
19
|
-
'\n - Jira in bulk (many issues at once), boards, sprints and filters: `acli` in `bash`, per the `atlassian` skill. Confluence and attachments have no `acli` command and stay on MCP.';
|
|
20
|
-
}
|
|
21
|
-
if (onPath('glab')) {
|
|
22
|
-
routing +=
|
|
23
|
-
'\n - GitLab releases, labels, milestones, snippets, CI artifacts, and any endpoint with no MCP tool: `glab` in `bash`. Issues, merge requests, pipelines and code search stay on MCP, which covers them well.';
|
|
24
|
-
}
|
|
25
|
-
return dedent `
|
|
26
|
-
<available-tools>
|
|
27
|
-
You have these tools available:
|
|
28
|
-
* **Read operations (use freely):** \`read\`, \`grep\`, \`ls\`.
|
|
29
|
-
- Use these aggressively to understand the system under test before proposing changes.
|
|
30
|
-
* **Write operations (restricted):** \`write\`, \`edit\`, \`bash\`.
|
|
31
|
-
- Requires explicit user confirmation for destructive or shared-state actions.
|
|
32
|
-
${extra} * **Internal Skills:** For QA-related tasks, check available skills first and prefer using them when applicable.
|
|
33
|
-
* **External Integrations:** Use MCP tools when they provide superior data or specialized integrations.
|
|
34
|
-
- Primary MCP (Testomat.io): Use Testomat.io MCP tools to extend functionality.
|
|
35
|
-
- Secondary MCP (Jira, GitHub, etc.): Invoke only when user explicitly asks or when remote context exploration is required.
|
|
36
|
-
${routing}
|
|
37
|
-
|
|
38
|
-
<tool-governance>
|
|
39
|
-
* **Prioritize Specificity:** Use \`read\` instead of \`cat\`, and \`edit\` instead of \`sed\`. Dedicated tools provide better error tracking and safety.
|
|
40
|
-
* **Parallel Execution:** Call independent tools in parallel to minimize latency. Sequential calls are reserved for operations with data dependencies.
|
|
41
|
-
* **Atomic Updates:** Mark tasks as complete in your internal state immediately upon execution. Do not batch status updates.
|
|
42
|
-
* **Analysis-First:** Use your own reasoning to guide tool selection. Do not wait for step-by-step instructions if discovery tools can provide the answer.
|
|
43
|
-
</tool-governance>
|
|
44
|
-
</available-tools>
|
|
45
|
-
`;
|
|
46
|
-
}
|
|
47
|
-
/** Is this CLI on PATH? Never tell the agent to use a binary this machine lacks. */
|
|
48
|
-
function onPath(bin) {
|
|
49
|
-
for (const dir of (process.env.PATH ?? '').split(delimiter)) {
|
|
50
|
-
if (!dir)
|
|
51
|
-
continue;
|
|
52
|
-
if (existsSync(join(dir, bin)) || existsSync(join(dir, `${bin}.exe`)))
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* CLIs Testeiya knows how to connect, probed on PATH — the same trio routed in
|
|
59
|
-
* `<available-tools>` above. Shared with the prompt's connections section so
|
|
60
|
-
* the two can never disagree about whether `gh` etc. exist.
|
|
61
|
-
*/
|
|
62
|
-
export const KNOWN_CLIS = [
|
|
63
|
-
{ bin: 'gh', label: 'gh (GitHub CLI)' },
|
|
64
|
-
{ bin: 'acli', label: 'acli (Atlassian CLI)' },
|
|
65
|
-
{ bin: 'glab', label: 'glab (GitLab CLI)' },
|
|
66
|
-
];
|
|
67
|
-
export function pathClis() {
|
|
68
|
-
return KNOWN_CLIS.filter((c) => onPath(c.bin)).map((c) => c.label);
|
|
69
|
-
}
|
|
70
|
-
//# sourceMappingURL=tools.js.map
|
package/dist/prompt/tools.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../prompt/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,OAA8B;IAClD,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9C,IAAI,OAAO,GAAG,gDAAgD,CAAC;IAC/D,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACjB,OAAO;YACL,8JAA8J,CAAC;IACnK,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACnB,OAAO;YACL,0LAA0L,CAAC;IAC/L,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACnB,OAAO;YACL,kNAAkN,CAAC;IACvN,CAAC;IACD,OAAO,MAAM,CAAA;;;;;;;EAOb,KAAK;;;;EAIL,OAAO;;;;;;;;;CASR,CAAC;AACF,CAAC;AAED,oFAAoF;AACpF,SAAS,MAAM,CAAC,GAAW;IACzB,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACrF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAqC;IAC1D,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,iBAAiB,EAAE;IACvC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,sBAAsB,EAAE;IAC9C,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,EAAE;CAC5C,CAAC;AAEF,MAAM,UAAU,QAAQ;IACtB,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AACrE,CAAC"}
|
package/dist/prompt/vocab.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The per-project config directory name, as the agent knows it. Part of the
|
|
3
|
-
* vocabulary the system prompt teaches — every path the prompt names below it
|
|
4
|
-
* (`.testeiya/manual-tests`, `.testeiya/project-info.json`, …) is built from
|
|
5
|
-
* this constant, so the prompt and the harness can never disagree about it.
|
|
6
|
-
*/
|
|
7
|
-
export const TESTEIYA_DIR_NAME = ".testeiya";
|
|
8
|
-
//# sourceMappingURL=vocab.js.map
|
package/dist/prompt/vocab.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"vocab.js","sourceRoot":"","sources":["../../prompt/vocab.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAC"}
|
package/prompt/comment-thread.ts
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import dedent from 'dedent';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* How an answer already posted stops being the current one, per host. The round
|
|
5
|
-
* is the same wherever the thread lives — find your marked comments, diff from
|
|
6
|
-
* the commit the last one carries, make it recede, write the current answer — so
|
|
7
|
-
* a host contributes only its own rules: which of the two strategies its API
|
|
8
|
-
* affords, and the facts about it that cannot be worked out from the API alone.
|
|
9
|
-
*
|
|
10
|
-
* The host comes from the environment, never from the remote. A remote says
|
|
11
|
-
* where the code lives; only the CI variables say we are in a job that has a
|
|
12
|
-
* subject to answer and a token to answer with.
|
|
13
|
-
*
|
|
14
|
-
* This table is the extension point. There is no default host: a job nothing
|
|
15
|
-
* claims falls to `generic`, which states the choice and lets the agent make it.
|
|
16
|
-
*/
|
|
17
|
-
const HOSTS = {
|
|
18
|
-
github: {
|
|
19
|
-
env: ['GITHUB_ACTIONS'],
|
|
20
|
-
rules: dedent`
|
|
21
|
-
**Append and collapse.** GitHub hides a whole comment, so leave the earlier ones where they are and fold each one with the GraphQL \`minimizeComment\` mutation, classifier \`OUTDATED\`. Issues and pull requests share the same comment API, so this is the same call on both.
|
|
22
|
-
|
|
23
|
-
Read comment bodies from \`body\`; \`body_text\` has the marker stripped out. Never \`gh pr comment --edit-last\` or \`--delete-last\`: they mean the last comment by this user, which in CI is a bot account shared with every other tool in the repository.`,
|
|
24
|
-
},
|
|
25
|
-
|
|
26
|
-
gitlab: {
|
|
27
|
-
env: ['GITLAB_CI'],
|
|
28
|
-
rules: dedent`
|
|
29
|
-
**Rewrite.** GitLab folds the body of a note but never the note itself, so a note per round leaves a column of headers behind. Keep one note in this thread and rewrite it: the current answer on top, the previous one under it inside a \`<details>\` block, stripped of the \`<details>\` block it already carried. Fold one generation, never a chain of them.
|
|
30
|
-
|
|
31
|
-
\`CI_JOB_TOKEN\` cannot write notes, so \`$GITLAB_TOKEN\` must carry a project access token with the \`api\` scope; report it as a blocker when it is empty. Use notes rather than discussions: a discussion is a resolvable thread, and an unresolved one blocks the merge wherever all threads must be resolved.`,
|
|
32
|
-
},
|
|
33
|
-
|
|
34
|
-
bitbucket: {
|
|
35
|
-
env: ['BITBUCKET_BUILD_NUMBER'],
|
|
36
|
-
rules: dedent`
|
|
37
|
-
**Append and collapse.** Bitbucket resolves a whole comment thread, so leave the earlier ones where they are and resolve each one. Only a top-level comment resolves; a reply answers 403.
|
|
38
|
-
|
|
39
|
-
\`$BITBUCKET_ACCESS_TOKEN\` carries the token; report it as a blocker when it is empty. Deleted comments stay in the list as blanked tombstones, so filter on \`deleted=false\`. A pull request caps at 200 comments, so post once per round and never twice. The marker may render as visible text here — keep it anyway, since finding your own comments matters more than a tidy first line.`,
|
|
40
|
-
},
|
|
41
|
-
|
|
42
|
-
generic: {
|
|
43
|
-
env: [],
|
|
44
|
-
rules: dedent`
|
|
45
|
-
**Find out which of the two applies.** If this host can hide, minimise, resolve or otherwise fold a whole comment, append the new answer and fold the earlier ones. If it can only edit, keep one comment and rewrite it, with the previous answer folded inside wherever the host renders collapsible markup.
|
|
46
|
-
|
|
47
|
-
If it can do neither, post the answer and say in your output that this host cannot collapse the earlier ones.`,
|
|
48
|
-
},
|
|
49
|
-
} satisfies Record<string, Host>;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Which host this job belongs to. `generic` when it is CI and nothing claims it,
|
|
53
|
-
* nothing at all when it is not CI — a developer's own checkout has no thread.
|
|
54
|
-
*/
|
|
55
|
-
export function threadHost(env: Environment): ThreadHost | null {
|
|
56
|
-
for (const [name, host] of Object.entries(HOSTS)) {
|
|
57
|
-
if (host.env.some((variable) => env[variable])) return name as ThreadHost;
|
|
58
|
-
}
|
|
59
|
-
if (env.CI) return 'generic';
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** What a comment of this thread opens with, and so what identifies it. */
|
|
64
|
-
export function threadMarker(thread: string): string {
|
|
65
|
-
return `<!-- testeiya thread=${thread}`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function commentThread(options: CommentThreadOptions): string {
|
|
69
|
-
const write = options.posts
|
|
70
|
-
? 'Your report is posted for you. Do not post it yourself.'
|
|
71
|
-
: 'Post it yourself, opening the body with that same marker line.';
|
|
72
|
-
return dedent`
|
|
73
|
-
<comment-thread>
|
|
74
|
-
This section governs threads you post into: a pull request, a merge request, an issue. It says nothing about any other kind of work.
|
|
75
|
-
|
|
76
|
-
A comment you write opens with exactly this line, and your earlier ones already carry it:
|
|
77
|
-
|
|
78
|
-
\`${options.marker}\`
|
|
79
|
-
|
|
80
|
-
Yours in this conversation are the ones whose \`thread=\` is \`${options.thread}\`. A comment carrying a different thread belongs to another conversation on the same subject — never touch it.
|
|
81
|
-
|
|
82
|
-
**Never delete a comment.** A human reply may be sitting under it, and everything here is reversible where a delete is not.
|
|
83
|
-
|
|
84
|
-
Each round:
|
|
85
|
-
|
|
86
|
-
1. Find your earlier comments — raw body starting \`${threadMarker(options.thread)}\`. Read the raw body; a rendered one may have dropped the marker.
|
|
87
|
-
2. The newest one is your complete answer as of the \`commit=\` in its marker, so \`git diff <that sha>...HEAD\` is what you have not seen.
|
|
88
|
-
3. Make the earlier ones recede, by the rule below.
|
|
89
|
-
4. Write the **complete current answer**, not a delta — everything earlier is folded, so a delta would leave the thread with no visible state. Open with a short "Since the last round" list of what was fixed, what is new and what is still open.
|
|
90
|
-
|
|
91
|
-
${write}
|
|
92
|
-
|
|
93
|
-
${indent(HOSTS[options.host].rules)}
|
|
94
|
-
</comment-thread>`;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// dedent trims the literal parts of a template, never what is interpolated into
|
|
98
|
-
// them, so a block spanning lines has to arrive already at the right column.
|
|
99
|
-
function indent(text: string): string {
|
|
100
|
-
return text.split('\n').join('\n ');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export type ThreadHost = keyof typeof HOSTS;
|
|
104
|
-
|
|
105
|
-
type Environment = Record<string, string | undefined>;
|
|
106
|
-
|
|
107
|
-
interface Host {
|
|
108
|
-
/** A variable only this host's CI sets. Empty means nothing claims it. */
|
|
109
|
-
env: string[];
|
|
110
|
-
/** Which strategy its API affords, and what cannot be guessed about it. */
|
|
111
|
-
rules: string;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export interface CommentThreadOptions {
|
|
115
|
-
host: ThreadHost;
|
|
116
|
-
/** Which conversation this run is, so parallel runs never touch each other. */
|
|
117
|
-
thread: string;
|
|
118
|
-
/**
|
|
119
|
-
* The exact marker line a comment opens with. Built by the CLI so a comment
|
|
120
|
-
* the agent posts itself is stamped the same way as one the CLI delivers —
|
|
121
|
-
* the next round finds both by the same prefix.
|
|
122
|
-
*/
|
|
123
|
-
marker: string;
|
|
124
|
-
/** True when the CLI posts the report itself, so the agent must not. */
|
|
125
|
-
posts?: boolean;
|
|
126
|
-
}
|
package/prompt/context.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import dedent from "dedent";
|
|
2
|
-
import { TESTEIYA_DIR_NAME } from "./vocab.js";
|
|
3
|
-
|
|
4
|
-
/** System-prompt section describing the workspace context; "" when none. */
|
|
5
|
-
export function contextPromptSection(
|
|
6
|
-
entries: ContextEntry[],
|
|
7
|
-
folders: ContextFolder[] = []
|
|
8
|
-
): string {
|
|
9
|
-
if (entries.length === 0 && folders.length === 0) return "";
|
|
10
|
-
return dedent`
|
|
11
|
-
<workspace-context>
|
|
12
|
-
This workspace has context attached — the user (or you, earlier) put it there for a purpose. Consult it before answering, and prefer it over assumptions about the project.
|
|
13
|
-
|
|
14
|
-
${contextLines(entries, folders)}
|
|
15
|
-
|
|
16
|
-
Everything whose path starts with \`${TESTEIYA_DIR_NAME}/\` is in a hidden dir: file-search tools skip hidden dirs by default, so search those explicitly (pass hidden:true, or prefix the path with \`${TESTEIYA_DIR_NAME}/\`). Any other path above is an ordinary workspace path the user attached — read it where it is. Linked folders and cloned repositories are reference material: read them, never modify them. A linked folder is a symlink — wildcard searches do not descend into it; search it with its own path prefix (e.g. \`${TESTEIYA_DIR_NAME}/<name>/\`). Documents under \`${TESTEIYA_DIR_NAME}/requirements\` and \`${TESTEIYA_DIR_NAME}/docs\` are specs and plans — use them when writing or reviewing tests.
|
|
17
|
-
</workspace-context>
|
|
18
|
-
`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Per-prompt notice when the context changed mid-session; appended to the next prompt. */
|
|
22
|
-
export function contextUpdateNotice(
|
|
23
|
-
entries: ContextEntry[],
|
|
24
|
-
folders: ContextFolder[] = []
|
|
25
|
-
): string {
|
|
26
|
-
if (entries.length === 0 && folders.length === 0) {
|
|
27
|
-
return dedent`
|
|
28
|
-
<workspace-context-update>
|
|
29
|
-
All extra workspace context was removed. Do not rely on it anymore.
|
|
30
|
-
</workspace-context-update>
|
|
31
|
-
`;
|
|
32
|
-
}
|
|
33
|
-
return dedent`
|
|
34
|
-
<workspace-context-update>
|
|
35
|
-
The workspace context just changed. It now contains:
|
|
36
|
-
|
|
37
|
-
${contextLines(entries, folders)}
|
|
38
|
-
|
|
39
|
-
This was done for a purpose — take it into account for this and future requests. Remember \`${TESTEIYA_DIR_NAME}/\` is hidden: search it with hidden:true or an explicit path prefix.
|
|
40
|
-
</workspace-context-update>
|
|
41
|
-
`;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function contextLines(entries: ContextEntry[], folders: ContextFolder[]): string {
|
|
45
|
-
const lines: string[] = [];
|
|
46
|
-
const covered = new Set(entries.map((e) => parentDir(e.path)));
|
|
47
|
-
for (const f of folders) {
|
|
48
|
-
if (covered.has(f.path)) continue;
|
|
49
|
-
lines.push(`- \`${f.path}/\` — ${folderPurpose(f.name)}`);
|
|
50
|
-
}
|
|
51
|
-
for (const e of entries) lines.push(`- ${describeEntry(e)}`);
|
|
52
|
-
return lines.join("\n");
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function folderPurpose(name: string): string {
|
|
56
|
-
if (name === "manual-tests") {
|
|
57
|
-
return "the project's manual test suites pulled from Testomat.io (*.test.md — THE manual tests of this project)";
|
|
58
|
-
}
|
|
59
|
-
if (name === "code") return "reference code added as context";
|
|
60
|
-
if (name === "requirements") return "requirements and specs";
|
|
61
|
-
if (name === "docs") return "test planning and strategy documents";
|
|
62
|
-
if (name === "auto-tests") return "automated test references";
|
|
63
|
-
return "exploratory testing setup";
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function parentDir(rel: string): string {
|
|
67
|
-
const idx = rel.lastIndexOf("/");
|
|
68
|
-
if (idx < 0) return "";
|
|
69
|
-
return rel.slice(0, idx);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function describeEntry(e: ContextEntry): string {
|
|
73
|
-
const date = e.addedAt?.split("T")[0] ?? "";
|
|
74
|
-
// A path outside the hidden dir is one the user attached where it already
|
|
75
|
-
// lives — it is part of the project, not reference material dropped beside it.
|
|
76
|
-
if (!e.path.startsWith(`${TESTEIYA_DIR_NAME}/`)) {
|
|
77
|
-
let what = "folder";
|
|
78
|
-
if (e.kind === "file") what = "file";
|
|
79
|
-
return `\`${e.path}\` — workspace ${what}, attached by the user (${date})`;
|
|
80
|
-
}
|
|
81
|
-
let from = "";
|
|
82
|
-
if (e.origin && e.origin !== e.name) from = ` from ${e.origin}`;
|
|
83
|
-
if (e.kind === "repo") return `\`${e.path}\` — git repository${from} (${date})`;
|
|
84
|
-
if (e.kind === "folder") return `\`${e.path}\` — local folder${from} (${date})`;
|
|
85
|
-
return `\`${e.path}\` — document${from} (${date})`;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export type ContextKind = "folder" | "repo" | "file";
|
|
89
|
-
|
|
90
|
-
/** A top-level `.testeiya` folder shown as a status-bar section. */
|
|
91
|
-
export interface ContextFolder {
|
|
92
|
-
name: string;
|
|
93
|
-
/** Relative to cwd (`.testeiya/<name>`). */
|
|
94
|
-
path: string;
|
|
95
|
-
/** Direct children (files + dirs, dot entries excluded). */
|
|
96
|
-
count: number;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export interface ContextEntry {
|
|
100
|
-
id: string;
|
|
101
|
-
kind: ContextKind;
|
|
102
|
-
name: string;
|
|
103
|
-
/** Location inside the workspace, relative to cwd (always under `.testeiya/`). */
|
|
104
|
-
path: string;
|
|
105
|
-
/** Where it came from: an absolute local path, a git URL, or the uploaded filename. */
|
|
106
|
-
origin: string;
|
|
107
|
-
addedAt: string;
|
|
108
|
-
}
|