@testchimp/cli 0.1.22 → 0.1.25

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.
@@ -44,6 +44,41 @@ function mergeBodies(flagBody, jsonInputRaw) {
44
44
  return flagBody;
45
45
  return deepMerge(flagBody, extra);
46
46
  }
47
+ /** Shared agent policy/traceability flags for mutating CRUD commands. */
48
+ function addAgentTraceabilityOptions(cmd) {
49
+ return cmd
50
+ .option("--workflow-id <id>", "Catalog workflow id for agent Activity")
51
+ .option("--workflow-execution-id <ulid>", "Stable ULID for the whole agent run")
52
+ .option("--policy-file <name>", "Policy filename (e.g. run-qa.policy.md)")
53
+ .option("--policy-version <semver>", "Policy version from frontmatter")
54
+ .option("--git-sha <sha>", "Git SHA (defaults to HEAD)")
55
+ .option("--actor-type <type>", "LOCAL_AGENT | CLOUD_AGENT")
56
+ .option("--user-id <id>", "Optional user id")
57
+ .option("--branch-name <name>", "Git branch name")
58
+ .option("--agent-model <model>", "Optional agent model id (agent/CLI only)");
59
+ }
60
+ function collectAgentTraceabilityFlags(opts) {
61
+ const body = {};
62
+ if (opts.workflowId)
63
+ body.workflowId = String(opts.workflowId).trim();
64
+ if (opts.workflowExecutionId)
65
+ body.workflowExecutionId = String(opts.workflowExecutionId).trim();
66
+ if (opts.policyFile)
67
+ body.policyFile = String(opts.policyFile).trim();
68
+ if (opts.policyVersion)
69
+ body.policyVersion = String(opts.policyVersion).trim();
70
+ if (opts.gitSha)
71
+ body.gitSha = String(opts.gitSha).trim();
72
+ if (opts.actorType)
73
+ body.actorType = String(opts.actorType).trim();
74
+ if (opts.userId)
75
+ body.userId = String(opts.userId).trim();
76
+ if (opts.branchName)
77
+ body.branchName = String(opts.branchName).trim();
78
+ if (opts.agentModel)
79
+ body.agentModel = String(opts.agentModel).trim();
80
+ return body;
81
+ }
47
82
  function stderrProgress(msg) {
48
83
  console.error(`[testchimp] ${msg}`);
49
84
  }
@@ -134,6 +169,7 @@ export function buildCliProgram() {
134
169
  .option("--environment <s>")
135
170
  .option("--branch-name <s>")
136
171
  .option("--scenario-id <id>")
172
+ .option("--test-id <id>")
137
173
  .option("--platform <web|ios|android>")
138
174
  .option("--file-paths <csv>")
139
175
  .option("--folder-path <path>")
@@ -147,6 +183,8 @@ export function buildCliProgram() {
147
183
  body.branchName = opts.branchName;
148
184
  if (opts.scenarioId)
149
185
  body.scenarioId = opts.scenarioId;
186
+ if (opts.testId)
187
+ body.testId = opts.testId;
150
188
  if (opts.platform)
151
189
  body.platform = opts.platform;
152
190
  const scope = {};
@@ -176,48 +214,50 @@ export function buildCliProgram() {
176
214
  const out = await runTool("fetch-execution-report", merged, { postMcp });
177
215
  console.log(out);
178
216
  });
179
- program
217
+ addAgentTraceabilityOptions(program
180
218
  .command("create-user-story")
181
219
  .description(TOOL_DEFINITIONS.find((t) => t.kebab === "create-user-story").description)
182
220
  .addOption(jsonInputOption())
183
221
  .requiredOption("--platform-file-path <path>")
184
- .requiredOption("--title <title>")
185
- .action(async (opts) => {
186
- const body = { platformFilePath: opts.platformFilePath, title: opts.title };
222
+ .requiredOption("--title <title>")).action(async (opts) => {
223
+ const body = {
224
+ platformFilePath: opts.platformFilePath,
225
+ title: opts.title,
226
+ ...collectAgentTraceabilityFlags(opts),
227
+ };
187
228
  const merged = mergeBodies(body, opts.jsonInput);
188
229
  const out = await runTool("create-user-story", merged, { postMcp });
189
230
  console.log(out);
190
231
  });
191
- program
232
+ addAgentTraceabilityOptions(program
192
233
  .command("create-test-scenario")
193
234
  .description(TOOL_DEFINITIONS.find((t) => t.kebab === "create-test-scenario").description)
194
235
  .addOption(jsonInputOption())
195
236
  .requiredOption("--platform-file-path <path>")
196
237
  .requiredOption("--title <title>")
197
- .requiredOption("--user-story-ordinal-id <n>")
198
- .action(async (opts) => {
238
+ .requiredOption("--user-story-ordinal-id <n>")).action(async (opts) => {
199
239
  const body = {
200
240
  platformFilePath: opts.platformFilePath,
201
241
  title: opts.title,
202
242
  userStoryOrdinalId: Number(opts.userStoryOrdinalId),
243
+ ...collectAgentTraceabilityFlags(opts),
203
244
  };
204
245
  const merged = mergeBodies(body, opts.jsonInput);
205
246
  const out = await runTool("create-test-scenario", merged, { postMcp });
206
247
  console.log(out);
207
248
  });
208
- program
249
+ addAgentTraceabilityOptions(program
209
250
  .command("update-user-story")
210
251
  .description(TOOL_DEFINITIONS.find((t) => t.kebab === "update-user-story").description)
211
252
  .addOption(jsonInputOption())
212
253
  .option("--content <markdown>", "full markdown including frontmatter")
213
- .option("--content-file <path>", "read markdown from file")
214
- .action(async (opts) => {
254
+ .option("--content-file <path>", "read markdown from file")).action(async (opts) => {
215
255
  let content = opts.content;
216
256
  if (opts.contentFile)
217
257
  content = await readFile(String(opts.contentFile), "utf8");
218
258
  if (!content)
219
259
  throw new Error("Provide --content or --content-file (or full body via --json-input)");
220
- const body = { content };
260
+ const body = { content, ...collectAgentTraceabilityFlags(opts) };
221
261
  const merged = mergeBodies(body, opts.jsonInput);
222
262
  const out = await runTool("update-user-story", merged, { postMcp });
223
263
  console.log(out);
@@ -286,15 +326,16 @@ export function buildCliProgram() {
286
326
  const out = await runTool("get-issue-details", { issueId: String(merged.issueId).trim() }, { postMcp });
287
327
  console.log(out);
288
328
  });
289
- program
329
+ addAgentTraceabilityOptions(program
290
330
  .command("update-issue-status")
291
331
  .description(TOOL_DEFINITIONS.find((t) => t.kebab === "update-issue-status").description)
292
332
  .addOption(jsonInputOption())
293
333
  .option("--issue-id <id>", "Issue ordinal id (#B-123, B-123, B123, or 123)")
294
334
  .option("--status <status>", "ACTIVE | IGNORED | FIXED | DUPLICATE | IN_PROGRESS_BUG | ARCHIVED_BUG | BLOCKED")
295
- .option("--ignore-reason <reason>", "When status=IGNORED: INTENDED_BEHAVIOUR | INACCURATE_ASSESSMENT | NOT_IMPORTANT")
296
- .action(async (opts) => {
297
- const body = {};
335
+ .option("--ignore-reason <reason>", "When status=IGNORED: INTENDED_BEHAVIOUR | INACCURATE_ASSESSMENT | NOT_IMPORTANT")).action(async (opts) => {
336
+ const body = {
337
+ ...collectAgentTraceabilityFlags(opts),
338
+ };
298
339
  if (opts.issueId)
299
340
  body.issueId = String(opts.issueId).trim();
300
341
  if (opts.status)
@@ -308,16 +349,10 @@ export function buildCliProgram() {
308
349
  if (!merged.status || String(merged.status).trim() === "") {
309
350
  throw new Error("status is required (ACTIVE | IGNORED | FIXED | DUPLICATE | IN_PROGRESS_BUG | ARCHIVED_BUG | BLOCKED)");
310
351
  }
311
- const out = await runTool("update-issue-status", {
312
- issueId: String(merged.issueId).trim(),
313
- status: String(merged.status).trim(),
314
- ...(merged.ignoreReason
315
- ? { ignoreReason: String(merged.ignoreReason).trim() }
316
- : {}),
317
- }, { postMcp });
352
+ const out = await runTool("update-issue-status", merged, { postMcp });
318
353
  console.log(out);
319
354
  });
320
- program
355
+ addAgentTraceabilityOptions(program
321
356
  .command("create-issue")
322
357
  .description(TOOL_DEFINITIONS.find((t) => t.kebab === "create-issue").description)
323
358
  .addOption(jsonInputOption())
@@ -332,9 +367,10 @@ export function buildCliProgram() {
332
367
  .option("--assignee <userId>", "Assignee user id")
333
368
  .option("--labels <csv>", "Comma-separated labels")
334
369
  .option("--source <name>", "External ingest source identifier (stored as label source:<name>)")
335
- .option("--environment <name>", "Environment tag (defaults to QA when omitted)")
336
- .action(async (opts) => {
337
- const body = {};
370
+ .option("--environment <name>", "Environment tag (defaults to QA when omitted)")).action(async (opts) => {
371
+ const body = {
372
+ ...collectAgentTraceabilityFlags(opts),
373
+ };
338
374
  if (opts.title)
339
375
  body.title = String(opts.title).trim();
340
376
  if (opts.description)
@@ -427,19 +463,18 @@ export function buildCliProgram() {
427
463
  }, { postMcp });
428
464
  console.log(out);
429
465
  });
430
- program
466
+ addAgentTraceabilityOptions(program
431
467
  .command("update-test-scenario")
432
468
  .description(TOOL_DEFINITIONS.find((t) => t.kebab === "update-test-scenario").description)
433
469
  .addOption(jsonInputOption())
434
470
  .option("--content <markdown>")
435
- .option("--content-file <path>")
436
- .action(async (opts) => {
471
+ .option("--content-file <path>")).action(async (opts) => {
437
472
  let content = opts.content;
438
473
  if (opts.contentFile)
439
474
  content = await readFile(String(opts.contentFile), "utf8");
440
475
  if (!content)
441
476
  throw new Error("Provide --content or --content-file (or full body via --json-input)");
442
- const body = { content };
477
+ const body = { content, ...collectAgentTraceabilityFlags(opts) };
443
478
  const merged = mergeBodies(body, opts.jsonInput);
444
479
  const out = await runTool("update-test-scenario", merged, { postMcp });
445
480
  console.log(out);
@@ -945,6 +980,7 @@ export function buildCliProgram() {
945
980
  .option("--actor-type <type>", "LOCAL_AGENT|CLOUD_AGENT (or local-agent|cloud-agent)")
946
981
  .option("--user-id <id>", "Optional user id for traceability")
947
982
  .option("--branch-name <name>", "Git branch")
983
+ .option("--agent-model <model>", "Optional agent model id (agent/CLI only)")
948
984
  .requiredOption("--entity-type <type>", "USER_STORY|SCENARIO|SMART_TEST|POLICY|ISSUE|TEST_EXECUTION|TEST_INVOCATION_BATCH|EXPLORATION|EVENT|WORKFLOW")
949
985
  .option("--entity-identity <ordinal>", "Project-scoped ordinal id (mutually exclusive with --test-json)")
950
986
  .option("--test-json <json>", "TestLocator JSON (folderPath/fileName/testSuite/testName)")
@@ -968,6 +1004,8 @@ export function buildCliProgram() {
968
1004
  body.userId = String(opts.userId);
969
1005
  if (opts.branchName)
970
1006
  body.branchName = String(opts.branchName);
1007
+ if (opts.agentModel)
1008
+ body.agentModel = String(opts.agentModel).trim();
971
1009
  if (opts.entityIdentity)
972
1010
  body.entityIdentity = String(opts.entityIdentity);
973
1011
  if (opts.testJson)
@@ -1029,6 +1067,28 @@ export function buildCliProgram() {
1029
1067
  }
1030
1068
  console.log(await runTool("upsert-policy", merged, { postMcp }));
1031
1069
  });
1070
+ program
1071
+ .command("upsert-plans-support-file")
1072
+ .description(TOOL_DEFINITIONS.find((t) => t.kebab === "upsert-plans-support-file").description)
1073
+ .addOption(jsonInputOption())
1074
+ .option("--file-path <path>", "path relative to mapped plans root (e.g. knowledge/workflow_plans/run-qa/<ulid>.plan.md)")
1075
+ .option("--content <markdown>", "full file content")
1076
+ .option("--content-file <path>", "read content from local file")
1077
+ .action(async (opts) => {
1078
+ let content = opts.content;
1079
+ if (opts.contentFile)
1080
+ content = await readFile(String(opts.contentFile), "utf8");
1081
+ const body = {};
1082
+ if (opts.filePath)
1083
+ body.filePath = String(opts.filePath);
1084
+ if (content !== undefined)
1085
+ body.content = content;
1086
+ const merged = mergeBodies(body, opts.jsonInput);
1087
+ if (!merged.filePath || merged.content === undefined || merged.content === null) {
1088
+ throw new Error("Provide --file-path and --content or --content-file (or full body via --json-input)");
1089
+ }
1090
+ console.log(await runTool("upsert-plans-support-file", merged, { postMcp }));
1091
+ });
1032
1092
  program.on("--help", () => {
1033
1093
  /* default */
1034
1094
  });
@@ -0,0 +1,22 @@
1
+ /** Flat CLI/MCP fields that map to AgentActionTraceability. */
2
+ export type AgentTraceabilityFields = {
3
+ workflowId?: string;
4
+ workflowExecutionId?: string;
5
+ policyFile?: string;
6
+ policyVersion?: string;
7
+ gitSha?: string;
8
+ actorType?: string;
9
+ userId?: string;
10
+ branchName?: string;
11
+ agentModel?: string;
12
+ /** Nested form (wins over flat when both present and non-empty). */
13
+ agentTraceability?: Record<string, unknown>;
14
+ };
15
+ /**
16
+ * Build camelCase AgentActionTraceability for MCP JSON bodies.
17
+ * Returns undefined unless the caller supplied explicit traceability intent
18
+ * **and** a non-empty workflowId (server requires workflow_id for inline Activity).
19
+ * Auto-fills gitSha / agentModel / userId only after that bar is met.
20
+ * Non-empty nested `agentTraceability` wins over flat for overlapping keys.
21
+ */
22
+ export declare function buildAgentTraceabilityPayload(a: AgentTraceabilityFields): Record<string, unknown> | undefined;
@@ -0,0 +1,95 @@
1
+ import { resolveGitHeadSha } from "./gitSha.js";
2
+ function nonEmptyString(v) {
3
+ if (v == null)
4
+ return undefined;
5
+ const s = String(v).trim();
6
+ return s === "" ? undefined : s;
7
+ }
8
+ function hasExplicitTraceabilityIntent(a) {
9
+ if (nonEmptyString(a.workflowId))
10
+ return true;
11
+ if (nonEmptyString(a.workflowExecutionId))
12
+ return true;
13
+ if (nonEmptyString(a.policyFile))
14
+ return true;
15
+ if (nonEmptyString(a.policyVersion))
16
+ return true;
17
+ if (nonEmptyString(a.gitSha))
18
+ return true;
19
+ if (nonEmptyString(a.actorType))
20
+ return true;
21
+ if (nonEmptyString(a.userId))
22
+ return true;
23
+ if (nonEmptyString(a.branchName))
24
+ return true;
25
+ if (nonEmptyString(a.agentModel))
26
+ return true;
27
+ if (a.agentTraceability && typeof a.agentTraceability === "object") {
28
+ return Object.keys(a.agentTraceability).some((k) => nonEmptyString(a.agentTraceability[k]) != null);
29
+ }
30
+ return false;
31
+ }
32
+ function normalizeActorType(raw) {
33
+ if (raw == null)
34
+ return undefined;
35
+ const s = String(raw).toUpperCase().replace(/-/g, "_");
36
+ if (s === "CLOUD_AGENT")
37
+ return "CLOUD_AGENT";
38
+ if (s === "LOCAL_AGENT")
39
+ return "LOCAL_AGENT";
40
+ return undefined;
41
+ }
42
+ /**
43
+ * Build camelCase AgentActionTraceability for MCP JSON bodies.
44
+ * Returns undefined unless the caller supplied explicit traceability intent
45
+ * **and** a non-empty workflowId (server requires workflow_id for inline Activity).
46
+ * Auto-fills gitSha / agentModel / userId only after that bar is met.
47
+ * Non-empty nested `agentTraceability` wins over flat for overlapping keys.
48
+ */
49
+ export function buildAgentTraceabilityPayload(a) {
50
+ if (!hasExplicitTraceabilityIntent(a)) {
51
+ return undefined;
52
+ }
53
+ const nested = a.agentTraceability &&
54
+ typeof a.agentTraceability === "object" &&
55
+ Object.keys(a.agentTraceability).some((k) => nonEmptyString(a.agentTraceability[k]) != null)
56
+ ? { ...a.agentTraceability }
57
+ : null;
58
+ const out = {};
59
+ const workflowId = nonEmptyString(nested?.workflowId) ?? nonEmptyString(a.workflowId);
60
+ const workflowExecutionId = nonEmptyString(nested?.workflowExecutionId) ?? nonEmptyString(a.workflowExecutionId);
61
+ const policyFile = nonEmptyString(nested?.policyFile) ?? nonEmptyString(a.policyFile);
62
+ const policyVersion = nonEmptyString(nested?.policyVersion) ?? nonEmptyString(a.policyVersion);
63
+ const gitShaExplicit = nonEmptyString(nested?.gitSha) ?? nonEmptyString(a.gitSha);
64
+ const actorType = normalizeActorType(nested?.actorType) ?? normalizeActorType(a.actorType);
65
+ const userId = nonEmptyString(nested?.userId) ??
66
+ nonEmptyString(a.userId) ??
67
+ nonEmptyString(process.env.TESTCHIMP_USER_ID);
68
+ const branchName = nonEmptyString(nested?.branchName) ?? nonEmptyString(a.branchName);
69
+ const agentModel = nonEmptyString(nested?.agentModel) ??
70
+ nonEmptyString(a.agentModel) ??
71
+ nonEmptyString(process.env.TESTCHIMP_AGENT_MODEL);
72
+ // Server requires workflow_id for inline mutation Activity — do not send orphan payloads.
73
+ if (!workflowId) {
74
+ return undefined;
75
+ }
76
+ out.workflowId = workflowId;
77
+ if (workflowExecutionId)
78
+ out.workflowExecutionId = workflowExecutionId;
79
+ if (policyFile)
80
+ out.policyFile = policyFile;
81
+ if (policyVersion)
82
+ out.policyVersion = policyVersion;
83
+ const gitSha = resolveGitHeadSha(gitShaExplicit);
84
+ if (gitSha)
85
+ out.gitSha = gitSha;
86
+ if (actorType)
87
+ out.actorType = actorType;
88
+ if (userId)
89
+ out.userId = userId;
90
+ if (branchName)
91
+ out.branchName = branchName;
92
+ if (agentModel)
93
+ out.agentModel = agentModel;
94
+ return out;
95
+ }
@@ -38,6 +38,7 @@ export declare const listExecutionInput: z.ZodObject<{
38
38
  }, z.core.$strip>>;
39
39
  branchName: z.ZodOptional<z.ZodString>;
40
40
  scenarioId: z.ZodOptional<z.ZodString>;
41
+ testId: z.ZodOptional<z.ZodString>;
41
42
  platform: z.ZodOptional<z.ZodEnum<{
42
43
  web: "web";
43
44
  ios: "ios";
@@ -54,17 +55,163 @@ export declare const fetchExecutionReportInput: z.ZodObject<{
54
55
  batchInvocationId: z.ZodOptional<z.ZodString>;
55
56
  jobId: z.ZodOptional<z.ZodString>;
56
57
  }, z.core.$strip>;
58
+ export declare const agentActorTypeSchema: z.ZodEnum<{
59
+ LOCAL_AGENT: "LOCAL_AGENT";
60
+ CLOUD_AGENT: "CLOUD_AGENT";
61
+ "local-agent": "local-agent";
62
+ "cloud-agent": "cloud-agent";
63
+ }>;
64
+ /** Nested AgentActionTraceability (agent_traceability.proto) for mutating MCP CRUDs. */
65
+ export declare const agentActionTraceabilitySchema: z.ZodObject<{
66
+ workflowId: z.ZodOptional<z.ZodString>;
67
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
68
+ policyFile: z.ZodOptional<z.ZodString>;
69
+ policyVersion: z.ZodOptional<z.ZodString>;
70
+ gitSha: z.ZodOptional<z.ZodString>;
71
+ actorType: z.ZodOptional<z.ZodEnum<{
72
+ LOCAL_AGENT: "LOCAL_AGENT";
73
+ CLOUD_AGENT: "CLOUD_AGENT";
74
+ "local-agent": "local-agent";
75
+ "cloud-agent": "cloud-agent";
76
+ }>>;
77
+ userId: z.ZodOptional<z.ZodString>;
78
+ branchName: z.ZodOptional<z.ZodString>;
79
+ agentModel: z.ZodOptional<z.ZodString>;
80
+ }, z.core.$strict>;
81
+ /** Flat + nested traceability fields shared by create/update MCP tools. */
82
+ export declare const agentTraceabilityFieldsSchema: z.ZodObject<{
83
+ workflowId: z.ZodOptional<z.ZodString>;
84
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
85
+ policyFile: z.ZodOptional<z.ZodString>;
86
+ policyVersion: z.ZodOptional<z.ZodString>;
87
+ gitSha: z.ZodOptional<z.ZodString>;
88
+ actorType: z.ZodOptional<z.ZodEnum<{
89
+ LOCAL_AGENT: "LOCAL_AGENT";
90
+ CLOUD_AGENT: "CLOUD_AGENT";
91
+ "local-agent": "local-agent";
92
+ "cloud-agent": "cloud-agent";
93
+ }>>;
94
+ userId: z.ZodOptional<z.ZodString>;
95
+ branchName: z.ZodOptional<z.ZodString>;
96
+ agentModel: z.ZodOptional<z.ZodString>;
97
+ agentTraceability: z.ZodOptional<z.ZodObject<{
98
+ workflowId: z.ZodOptional<z.ZodString>;
99
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
100
+ policyFile: z.ZodOptional<z.ZodString>;
101
+ policyVersion: z.ZodOptional<z.ZodString>;
102
+ gitSha: z.ZodOptional<z.ZodString>;
103
+ actorType: z.ZodOptional<z.ZodEnum<{
104
+ LOCAL_AGENT: "LOCAL_AGENT";
105
+ CLOUD_AGENT: "CLOUD_AGENT";
106
+ "local-agent": "local-agent";
107
+ "cloud-agent": "cloud-agent";
108
+ }>>;
109
+ userId: z.ZodOptional<z.ZodString>;
110
+ branchName: z.ZodOptional<z.ZodString>;
111
+ agentModel: z.ZodOptional<z.ZodString>;
112
+ }, z.core.$strict>>;
113
+ }, z.core.$strip>;
57
114
  export declare const createUserStoryInput: z.ZodObject<{
58
115
  platformFilePath: z.ZodString;
59
116
  title: z.ZodString;
117
+ workflowId: z.ZodOptional<z.ZodString>;
118
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
119
+ policyFile: z.ZodOptional<z.ZodString>;
120
+ policyVersion: z.ZodOptional<z.ZodString>;
121
+ gitSha: z.ZodOptional<z.ZodString>;
122
+ actorType: z.ZodOptional<z.ZodEnum<{
123
+ LOCAL_AGENT: "LOCAL_AGENT";
124
+ CLOUD_AGENT: "CLOUD_AGENT";
125
+ "local-agent": "local-agent";
126
+ "cloud-agent": "cloud-agent";
127
+ }>>;
128
+ userId: z.ZodOptional<z.ZodString>;
129
+ branchName: z.ZodOptional<z.ZodString>;
130
+ agentModel: z.ZodOptional<z.ZodString>;
131
+ agentTraceability: z.ZodOptional<z.ZodObject<{
132
+ workflowId: z.ZodOptional<z.ZodString>;
133
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
134
+ policyFile: z.ZodOptional<z.ZodString>;
135
+ policyVersion: z.ZodOptional<z.ZodString>;
136
+ gitSha: z.ZodOptional<z.ZodString>;
137
+ actorType: z.ZodOptional<z.ZodEnum<{
138
+ LOCAL_AGENT: "LOCAL_AGENT";
139
+ CLOUD_AGENT: "CLOUD_AGENT";
140
+ "local-agent": "local-agent";
141
+ "cloud-agent": "cloud-agent";
142
+ }>>;
143
+ userId: z.ZodOptional<z.ZodString>;
144
+ branchName: z.ZodOptional<z.ZodString>;
145
+ agentModel: z.ZodOptional<z.ZodString>;
146
+ }, z.core.$strict>>;
60
147
  }, z.core.$strip>;
61
148
  export declare const createTestScenarioInput: z.ZodObject<{
62
149
  platformFilePath: z.ZodString;
63
150
  title: z.ZodString;
64
151
  userStoryOrdinalId: z.ZodCoercedNumber<unknown>;
152
+ workflowId: z.ZodOptional<z.ZodString>;
153
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
154
+ policyFile: z.ZodOptional<z.ZodString>;
155
+ policyVersion: z.ZodOptional<z.ZodString>;
156
+ gitSha: z.ZodOptional<z.ZodString>;
157
+ actorType: z.ZodOptional<z.ZodEnum<{
158
+ LOCAL_AGENT: "LOCAL_AGENT";
159
+ CLOUD_AGENT: "CLOUD_AGENT";
160
+ "local-agent": "local-agent";
161
+ "cloud-agent": "cloud-agent";
162
+ }>>;
163
+ userId: z.ZodOptional<z.ZodString>;
164
+ branchName: z.ZodOptional<z.ZodString>;
165
+ agentModel: z.ZodOptional<z.ZodString>;
166
+ agentTraceability: z.ZodOptional<z.ZodObject<{
167
+ workflowId: z.ZodOptional<z.ZodString>;
168
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
169
+ policyFile: z.ZodOptional<z.ZodString>;
170
+ policyVersion: z.ZodOptional<z.ZodString>;
171
+ gitSha: z.ZodOptional<z.ZodString>;
172
+ actorType: z.ZodOptional<z.ZodEnum<{
173
+ LOCAL_AGENT: "LOCAL_AGENT";
174
+ CLOUD_AGENT: "CLOUD_AGENT";
175
+ "local-agent": "local-agent";
176
+ "cloud-agent": "cloud-agent";
177
+ }>>;
178
+ userId: z.ZodOptional<z.ZodString>;
179
+ branchName: z.ZodOptional<z.ZodString>;
180
+ agentModel: z.ZodOptional<z.ZodString>;
181
+ }, z.core.$strict>>;
65
182
  }, z.core.$strip>;
66
183
  export declare const updatePlanMarkdownInput: z.ZodObject<{
67
184
  content: z.ZodString;
185
+ workflowId: z.ZodOptional<z.ZodString>;
186
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
187
+ policyFile: z.ZodOptional<z.ZodString>;
188
+ policyVersion: z.ZodOptional<z.ZodString>;
189
+ gitSha: z.ZodOptional<z.ZodString>;
190
+ actorType: z.ZodOptional<z.ZodEnum<{
191
+ LOCAL_AGENT: "LOCAL_AGENT";
192
+ CLOUD_AGENT: "CLOUD_AGENT";
193
+ "local-agent": "local-agent";
194
+ "cloud-agent": "cloud-agent";
195
+ }>>;
196
+ userId: z.ZodOptional<z.ZodString>;
197
+ branchName: z.ZodOptional<z.ZodString>;
198
+ agentModel: z.ZodOptional<z.ZodString>;
199
+ agentTraceability: z.ZodOptional<z.ZodObject<{
200
+ workflowId: z.ZodOptional<z.ZodString>;
201
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
202
+ policyFile: z.ZodOptional<z.ZodString>;
203
+ policyVersion: z.ZodOptional<z.ZodString>;
204
+ gitSha: z.ZodOptional<z.ZodString>;
205
+ actorType: z.ZodOptional<z.ZodEnum<{
206
+ LOCAL_AGENT: "LOCAL_AGENT";
207
+ CLOUD_AGENT: "CLOUD_AGENT";
208
+ "local-agent": "local-agent";
209
+ "cloud-agent": "cloud-agent";
210
+ }>>;
211
+ userId: z.ZodOptional<z.ZodString>;
212
+ branchName: z.ZodOptional<z.ZodString>;
213
+ agentModel: z.ZodOptional<z.ZodString>;
214
+ }, z.core.$strict>>;
68
215
  }, z.core.$strip>;
69
216
  export declare const markPlanItemsImplementationDoneInput: z.ZodObject<{
70
217
  scenarioOrdinalIds: z.ZodOptional<z.ZodArray<z.ZodCoercedNumber<unknown>>>;
@@ -103,6 +250,36 @@ export declare const updateIssueStatusInput: z.ZodObject<{
103
250
  INACCURATE_ASSESSMENT: "INACCURATE_ASSESSMENT";
104
251
  NOT_IMPORTANT: "NOT_IMPORTANT";
105
252
  }>>;
253
+ workflowId: z.ZodOptional<z.ZodString>;
254
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
255
+ policyFile: z.ZodOptional<z.ZodString>;
256
+ policyVersion: z.ZodOptional<z.ZodString>;
257
+ gitSha: z.ZodOptional<z.ZodString>;
258
+ actorType: z.ZodOptional<z.ZodEnum<{
259
+ LOCAL_AGENT: "LOCAL_AGENT";
260
+ CLOUD_AGENT: "CLOUD_AGENT";
261
+ "local-agent": "local-agent";
262
+ "cloud-agent": "cloud-agent";
263
+ }>>;
264
+ userId: z.ZodOptional<z.ZodString>;
265
+ branchName: z.ZodOptional<z.ZodString>;
266
+ agentModel: z.ZodOptional<z.ZodString>;
267
+ agentTraceability: z.ZodOptional<z.ZodObject<{
268
+ workflowId: z.ZodOptional<z.ZodString>;
269
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
270
+ policyFile: z.ZodOptional<z.ZodString>;
271
+ policyVersion: z.ZodOptional<z.ZodString>;
272
+ gitSha: z.ZodOptional<z.ZodString>;
273
+ actorType: z.ZodOptional<z.ZodEnum<{
274
+ LOCAL_AGENT: "LOCAL_AGENT";
275
+ CLOUD_AGENT: "CLOUD_AGENT";
276
+ "local-agent": "local-agent";
277
+ "cloud-agent": "cloud-agent";
278
+ }>>;
279
+ userId: z.ZodOptional<z.ZodString>;
280
+ branchName: z.ZodOptional<z.ZodString>;
281
+ agentModel: z.ZodOptional<z.ZodString>;
282
+ }, z.core.$strict>>;
106
283
  }, z.core.$strip>;
107
284
  export declare const createIssueInput: z.ZodObject<{
108
285
  title: z.ZodString;
@@ -169,6 +346,36 @@ export declare const createIssueInput: z.ZodObject<{
169
346
  environment: z.ZodOptional<z.ZodString>;
170
347
  attachments: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
171
348
  artifactReference: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
349
+ workflowId: z.ZodOptional<z.ZodString>;
350
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
351
+ policyFile: z.ZodOptional<z.ZodString>;
352
+ policyVersion: z.ZodOptional<z.ZodString>;
353
+ gitSha: z.ZodOptional<z.ZodString>;
354
+ actorType: z.ZodOptional<z.ZodEnum<{
355
+ LOCAL_AGENT: "LOCAL_AGENT";
356
+ CLOUD_AGENT: "CLOUD_AGENT";
357
+ "local-agent": "local-agent";
358
+ "cloud-agent": "cloud-agent";
359
+ }>>;
360
+ userId: z.ZodOptional<z.ZodString>;
361
+ branchName: z.ZodOptional<z.ZodString>;
362
+ agentModel: z.ZodOptional<z.ZodString>;
363
+ agentTraceability: z.ZodOptional<z.ZodObject<{
364
+ workflowId: z.ZodOptional<z.ZodString>;
365
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
366
+ policyFile: z.ZodOptional<z.ZodString>;
367
+ policyVersion: z.ZodOptional<z.ZodString>;
368
+ gitSha: z.ZodOptional<z.ZodString>;
369
+ actorType: z.ZodOptional<z.ZodEnum<{
370
+ LOCAL_AGENT: "LOCAL_AGENT";
371
+ CLOUD_AGENT: "CLOUD_AGENT";
372
+ "local-agent": "local-agent";
373
+ "cloud-agent": "cloud-agent";
374
+ }>>;
375
+ userId: z.ZodOptional<z.ZodString>;
376
+ branchName: z.ZodOptional<z.ZodString>;
377
+ agentModel: z.ZodOptional<z.ZodString>;
378
+ }, z.core.$strict>>;
172
379
  }, z.core.$strip>;
173
380
  export declare const emptyInput: z.ZodObject<{}, z.core.$strip>;
174
381
  export declare const getBranchSpecificEndpointConfigInput: z.ZodObject<{
@@ -735,8 +942,8 @@ export declare const requirementFindingUserStateSchema: z.ZodEnum<{
735
942
  }>;
736
943
  /** RequirementQualityReportSource — proto enum names. */
737
944
  export declare const requirementQualityReportSourceSchema: z.ZodEnum<{
738
- CLOUD: "CLOUD";
739
945
  LOCAL_AGENT: "LOCAL_AGENT";
946
+ CLOUD: "CLOUD";
740
947
  }>;
741
948
  /** SuggestedFixKind — proto enum names. */
742
949
  export declare const suggestedFixKindSchema: z.ZodEnum<{
@@ -864,8 +1071,8 @@ export declare const requirementQualityReportSchema: z.ZodObject<{
864
1071
  title: z.ZodOptional<z.ZodString>;
865
1072
  }, z.core.$strip>>;
866
1073
  source: z.ZodOptional<z.ZodEnum<{
867
- CLOUD: "CLOUD";
868
1074
  LOCAL_AGENT: "LOCAL_AGENT";
1075
+ CLOUD: "CLOUD";
869
1076
  }>>;
870
1077
  metrics: z.ZodOptional<z.ZodObject<{
871
1078
  overall: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
@@ -949,8 +1156,8 @@ export declare const reportRequirementQualityFindingsInput: z.ZodObject<{
949
1156
  title: z.ZodOptional<z.ZodString>;
950
1157
  }, z.core.$strip>>;
951
1158
  source: z.ZodOptional<z.ZodEnum<{
952
- CLOUD: "CLOUD";
953
1159
  LOCAL_AGENT: "LOCAL_AGENT";
1160
+ CLOUD: "CLOUD";
954
1161
  }>>;
955
1162
  metrics: z.ZodOptional<z.ZodObject<{
956
1163
  overall: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
@@ -1020,12 +1227,6 @@ export declare const reportRequirementQualityFindingsInput: z.ZodObject<{
1020
1227
  subjectEntityId: z.ZodOptional<z.ZodString>;
1021
1228
  ordinalId: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
1022
1229
  }, z.core.$strip>;
1023
- export declare const agentActorTypeSchema: z.ZodEnum<{
1024
- LOCAL_AGENT: "LOCAL_AGENT";
1025
- CLOUD_AGENT: "CLOUD_AGENT";
1026
- "local-agent": "local-agent";
1027
- "cloud-agent": "cloud-agent";
1028
- }>;
1029
1230
  /** Closed vocabulary for report-agent-action entity_type (agent_workflow.proto AgentActionEntityType). */
1030
1231
  export declare const agentActionEntityTypeSchema: z.ZodEnum<{
1031
1232
  SMART_TEST: "SMART_TEST";
@@ -1071,6 +1272,23 @@ export declare const reportAgentActionInput: z.ZodObject<{
1071
1272
  }>>;
1072
1273
  userId: z.ZodOptional<z.ZodString>;
1073
1274
  branchName: z.ZodOptional<z.ZodString>;
1275
+ agentModel: z.ZodOptional<z.ZodString>;
1276
+ traceability: z.ZodOptional<z.ZodObject<{
1277
+ workflowId: z.ZodOptional<z.ZodString>;
1278
+ workflowExecutionId: z.ZodOptional<z.ZodString>;
1279
+ policyFile: z.ZodOptional<z.ZodString>;
1280
+ policyVersion: z.ZodOptional<z.ZodString>;
1281
+ gitSha: z.ZodOptional<z.ZodString>;
1282
+ actorType: z.ZodOptional<z.ZodEnum<{
1283
+ LOCAL_AGENT: "LOCAL_AGENT";
1284
+ CLOUD_AGENT: "CLOUD_AGENT";
1285
+ "local-agent": "local-agent";
1286
+ "cloud-agent": "cloud-agent";
1287
+ }>>;
1288
+ userId: z.ZodOptional<z.ZodString>;
1289
+ branchName: z.ZodOptional<z.ZodString>;
1290
+ agentModel: z.ZodOptional<z.ZodString>;
1291
+ }, z.core.$strict>>;
1074
1292
  entityType: z.ZodEnum<{
1075
1293
  SMART_TEST: "SMART_TEST";
1076
1294
  SCENARIO: "SCENARIO";
@@ -1133,4 +1351,8 @@ export declare const upsertPolicyInput: z.ZodObject<{
1133
1351
  policyFileName: z.ZodString;
1134
1352
  content: z.ZodString;
1135
1353
  }, z.core.$strip>;
1354
+ export declare const upsertPlansSupportFileInput: z.ZodObject<{
1355
+ filePath: z.ZodString;
1356
+ content: z.ZodString;
1357
+ }, z.core.$strip>;
1136
1358
  export declare const listWorkflowCatalogInput: z.ZodObject<{}, z.core.$strip>;
@@ -33,6 +33,7 @@ export const listExecutionInput = z.object({
33
33
  scope: scopeSchema,
34
34
  branchName: z.string().optional(),
35
35
  scenarioId: z.string().optional(),
36
+ testId: z.string().optional(),
36
37
  platform: executionPlatformSchema.optional(),
37
38
  dimensionFilters: z.array(executionJobDimensionFilterSchema).optional(),
38
39
  limit: z.number().int().positive().max(500).optional(),
@@ -53,18 +54,46 @@ export const fetchExecutionReportInput = z
53
54
  });
54
55
  }
55
56
  });
57
+ export const agentActorTypeSchema = z.enum(["LOCAL_AGENT", "CLOUD_AGENT", "local-agent", "cloud-agent"]);
58
+ /** Nested AgentActionTraceability (agent_traceability.proto) for mutating MCP CRUDs. */
59
+ export const agentActionTraceabilitySchema = z
60
+ .object({
61
+ workflowId: z.string().optional(),
62
+ workflowExecutionId: z.string().optional(),
63
+ policyFile: z.string().optional(),
64
+ policyVersion: z.string().optional(),
65
+ gitSha: z.string().optional(),
66
+ actorType: agentActorTypeSchema.optional(),
67
+ userId: z.string().optional(),
68
+ branchName: z.string().optional(),
69
+ agentModel: z.string().optional(),
70
+ })
71
+ .strict();
72
+ /** Flat + nested traceability fields shared by create/update MCP tools. */
73
+ export const agentTraceabilityFieldsSchema = z.object({
74
+ workflowId: z.string().optional(),
75
+ workflowExecutionId: z.string().optional(),
76
+ policyFile: z.string().optional(),
77
+ policyVersion: z.string().optional(),
78
+ gitSha: z.string().optional(),
79
+ actorType: agentActorTypeSchema.optional(),
80
+ userId: z.string().optional(),
81
+ branchName: z.string().optional(),
82
+ agentModel: z.string().optional(),
83
+ agentTraceability: agentActionTraceabilitySchema.optional(),
84
+ });
56
85
  export const createUserStoryInput = z.object({
57
86
  platformFilePath: z.string().min(1),
58
87
  title: z.string().min(1),
59
- });
88
+ }).merge(agentTraceabilityFieldsSchema);
60
89
  export const createTestScenarioInput = z.object({
61
90
  platformFilePath: z.string().min(1),
62
91
  title: z.string().min(1),
63
92
  userStoryOrdinalId: z.coerce.number().int().positive(),
64
- });
93
+ }).merge(agentTraceabilityFieldsSchema);
65
94
  export const updatePlanMarkdownInput = z.object({
66
95
  content: z.string().min(1),
67
- });
96
+ }).merge(agentTraceabilityFieldsSchema);
68
97
  export const markPlanItemsImplementationDoneInput = z.object({
69
98
  scenarioOrdinalIds: z.array(z.coerce.number().int().positive()).optional(),
70
99
  userStoryOrdinalIds: z.array(z.coerce.number().int().positive()).optional(),
@@ -105,7 +134,7 @@ export const updateIssueStatusInput = z.object({
105
134
  ignoreReason: z
106
135
  .enum(["INTENDED_BEHAVIOUR", "INACCURATE_ASSESSMENT", "NOT_IMPORTANT"])
107
136
  .optional(),
108
- });
137
+ }).merge(agentTraceabilityFieldsSchema);
109
138
  const linkedEntityTypeSchema = z.enum([
110
139
  "STORY",
111
140
  "SCENARIO",
@@ -171,7 +200,7 @@ export const createIssueInput = z.object({
171
200
  environment: z.string().optional(),
172
201
  attachments: z.array(z.record(z.string(), z.unknown())).optional(),
173
202
  artifactReference: z.record(z.string(), z.unknown()).optional(),
174
- });
203
+ }).merge(agentTraceabilityFieldsSchema);
175
204
  export const emptyInput = z.object({});
176
205
  export const getBranchSpecificEndpointConfigInput = z.object({
177
206
  branchName: z.string().optional(),
@@ -507,7 +536,6 @@ export const reportRequirementQualityFindingsInput = z
507
536
  });
508
537
  }
509
538
  });
510
- export const agentActorTypeSchema = z.enum(["LOCAL_AGENT", "CLOUD_AGENT", "local-agent", "cloud-agent"]);
511
539
  /** Closed vocabulary for report-agent-action entity_type (agent_workflow.proto AgentActionEntityType). */
512
540
  export const agentActionEntityTypeSchema = z.enum([
513
541
  "USER_STORY",
@@ -549,6 +577,8 @@ export const reportAgentActionInput = z
549
577
  actorType: agentActorTypeSchema.optional(),
550
578
  userId: z.string().optional(),
551
579
  branchName: z.string().optional(),
580
+ agentModel: z.string().optional(),
581
+ traceability: agentActionTraceabilitySchema.optional(),
552
582
  entityType: agentActionEntityTypeSchema,
553
583
  /** Project-scoped ordinal id (or explicitly provided execution/batch id). Mutually exclusive with `test`. */
554
584
  entityIdentity: z.string().optional(),
@@ -653,4 +683,9 @@ export const upsertPolicyInput = z.object({
653
683
  policyFileName: z.string().min(1),
654
684
  content: z.string().min(1),
655
685
  });
686
+ export const upsertPlansSupportFileInput = z.object({
687
+ /** Path relative to mapped plans root (e.g. knowledge/workflow_plans/run-qa/<ulid>.plan.md). */
688
+ filePath: z.string().min(1),
689
+ content: z.string().min(1),
690
+ });
656
691
  export const listWorkflowCatalogInput = z.object({});
@@ -2,6 +2,7 @@ import { normalizeScope } from "./normalize.js";
2
2
  import { runProvisionEphemeralEnvironmentAndWait } from "./ephemeralWait.js";
3
3
  import * as S from "./schemas.js";
4
4
  import { resolveGitHeadSha } from "./gitSha.js";
5
+ import { buildAgentTraceabilityPayload } from "./agentTraceability.js";
5
6
  function platformToProtoEnum(platform) {
6
7
  switch (platform) {
7
8
  case "ios":
@@ -68,6 +69,8 @@ function listExecutionBody(args) {
68
69
  body.branchName = args.branchName.trim();
69
70
  if (args.scenarioId != null && args.scenarioId.trim() !== "")
70
71
  body.scenarioId = args.scenarioId.trim();
72
+ if (args.testId != null && args.testId.trim() !== "")
73
+ body.testId = args.testId.trim();
71
74
  const dimensionFilters = [...(args.dimensionFilters ?? [])];
72
75
  if (args.platform != null) {
73
76
  const hasPlatformFilter = dimensionFilters.some((f) => f.dimension === "PLATFORM_EXECUTION_JOB_FILTER_DIMENSION");
@@ -138,7 +141,8 @@ export const TOOL_DEFINITIONS = [
138
141
  },
139
142
  {
140
143
  kebab: "get-execution-history",
141
- description: "Fetch SmartTest execution history for an optional platform-rooted folder scope, or for a scenario when scenarioId is set. " +
144
+ description: "Fetch SmartTest execution history for a testId (top 5 recent runs), an optional platform-rooted folder/file scope, or a scenario when scenarioId is set. " +
145
+ "Prefer testId when you have it from fetch-execution-report. Typically omit environment to avoid env scoping. " +
142
146
  "Use branchName and scope.filePaths as for coverage. Optional platform (web|ios|android) and dimensionFilters narrow results.",
143
147
  inputSchema: S.listExecutionInput,
144
148
  execute: async (args, { postMcp }) => {
@@ -167,14 +171,20 @@ export const TOOL_DEFINITIONS = [
167
171
  "Response includes content: canonical stub markdown already containing id: US-<ordinalId>. " +
168
172
  "BLOCKING workflow: call this FIRST → Write the returned content to the repo plans/stories path " +
169
173
  "(edit body as needed but keep id:) → call update-user-story with the full markdown. " +
170
- "Never write story markdown that omits id. platformFilePath must be under plans/stories/ and end with .md.",
174
+ "Never write story markdown that omits id. platformFilePath must be under plans/stories/ and end with .md. " +
175
+ "Optional agentTraceability (or flat workflowId/workflowExecutionId/policyFile/policyVersion/gitSha/…) " +
176
+ "records AGENT_WORKFLOW_ACTIVITY inline — no separate report-agent-action needed for this create.",
171
177
  inputSchema: S.createUserStoryInput,
172
178
  execute: async (args, { postMcp }) => {
173
179
  const a = args;
174
- return postMcp("/api/mcp/create_user_story", {
180
+ const body = {
175
181
  platformFilePath: a.platformFilePath,
176
182
  title: a.title,
177
- });
183
+ };
184
+ const trace = buildAgentTraceabilityPayload(a);
185
+ if (trace)
186
+ body.agentTraceability = trace;
187
+ return postMcp("/api/mcp/create_user_story", body);
178
188
  },
179
189
  },
180
190
  {
@@ -185,37 +195,52 @@ export const TOOL_DEFINITIONS = [
185
195
  "(edit body as needed but keep id: and story:) → call update-test-scenario with the full markdown. " +
186
196
  "Never write scenario markdown that omits id. update-test-scenario rejects missing id/story with a clear error. " +
187
197
  "platformFilePath must be under plans/scenarios/ and end with .md. " +
188
- "userStoryOrdinalId is the numeric part of the parent US-<n> id.",
198
+ "userStoryOrdinalId is the numeric part of the parent US-<n> id. " +
199
+ "Optional agentTraceability records Activity inline (no separate report-agent-action for this create).",
189
200
  inputSchema: S.createTestScenarioInput,
190
201
  execute: async (args, { postMcp }) => {
191
202
  const a = args;
192
- return postMcp("/api/mcp/create_test_scenario", {
203
+ const body = {
193
204
  platformFilePath: a.platformFilePath,
194
205
  title: a.title,
195
206
  userStoryOrdinalId: a.userStoryOrdinalId,
196
- });
207
+ };
208
+ const trace = buildAgentTraceabilityPayload(a);
209
+ if (trace)
210
+ body.agentTraceability = trace;
211
+ return postMcp("/api/mcp/create_test_scenario", body);
197
212
  },
198
213
  },
199
214
  {
200
215
  kebab: "update-user-story",
201
216
  description: "Sync a user story markdown file to the platform after local edits. " +
202
217
  "Requires frontmatter id: US-<n> (platform-issued). Missing id returns an error telling you to call create-user-story first. " +
203
- "Parses frontmatter (id, title, priority) and updates the linked support file and entity.",
218
+ "Parses frontmatter (id, title, priority) and updates the linked support file and entity. " +
219
+ "Optional agentTraceability records UPDATED Activity inline.",
204
220
  inputSchema: S.updatePlanMarkdownInput,
205
221
  execute: async (args, { postMcp }) => {
206
222
  const a = args;
207
- return postMcp("/api/mcp/update_user_story", { content: a.content });
223
+ const body = { content: a.content };
224
+ const trace = buildAgentTraceabilityPayload(a);
225
+ if (trace)
226
+ body.agentTraceability = trace;
227
+ return postMcp("/api/mcp/update_user_story", body);
208
228
  },
209
229
  },
210
230
  {
211
231
  kebab: "update-test-scenario",
212
232
  description: "Sync a test scenario markdown file to the platform after local edits. " +
213
233
  "Requires frontmatter id: TS-<n> and story: US-<n>. Missing either returns an error telling you to call create-test-scenario first. " +
214
- "Parses frontmatter and updates linking if story changes.",
234
+ "Parses frontmatter and updates linking if story changes. " +
235
+ "Optional agentTraceability records UPDATED Activity inline.",
215
236
  inputSchema: S.updatePlanMarkdownInput,
216
237
  execute: async (args, { postMcp }) => {
217
238
  const a = args;
218
- return postMcp("/api/mcp/update_test_scenario", { content: a.content });
239
+ const body = { content: a.content };
240
+ const trace = buildAgentTraceabilityPayload(a);
241
+ if (trace)
242
+ body.agentTraceability = trace;
243
+ return postMcp("/api/mcp/update_test_scenario", body);
219
244
  },
220
245
  },
221
246
  {
@@ -275,7 +300,8 @@ export const TOOL_DEFINITIONS = [
275
300
  description: "Update a TestChimp issue status by ordinal id (same flexible issueId formats as get-issue-details). " +
276
301
  "status must be one of: ACTIVE, IGNORED, FIXED, DUPLICATE, IN_PROGRESS_BUG, ARCHIVED_BUG, BLOCKED. " +
277
302
  "For /testchimp fix issue: set IN_PROGRESS_BUG after applying a code fix; set FIXED only after user confirmation / commits pushed. " +
278
- "Optional ignoreReason when status is IGNORED: INTENDED_BEHAVIOUR | INACCURATE_ASSESSMENT | NOT_IMPORTANT.",
303
+ "Optional ignoreReason when status is IGNORED: INTENDED_BEHAVIOUR | INACCURATE_ASSESSMENT | NOT_IMPORTANT. " +
304
+ "Optional agentTraceability records UPDATED Activity inline.",
279
305
  inputSchema: S.updateIssueStatusInput,
280
306
  execute: async (args, { postMcp }) => {
281
307
  const a = args;
@@ -285,6 +311,9 @@ export const TOOL_DEFINITIONS = [
285
311
  };
286
312
  if (a.ignoreReason)
287
313
  body.ignoreReason = a.ignoreReason;
314
+ const trace = buildAgentTraceabilityPayload(a);
315
+ if (trace)
316
+ body.agentTraceability = trace;
288
317
  return postMcp("/api/mcp/update_issue_status", body);
289
318
  },
290
319
  },
@@ -294,6 +323,8 @@ export const TOOL_DEFINITIONS = [
294
323
  "Use simple fields for common creates, or pass the full curated contract via --json-input " +
295
324
  "(description, issueType, category, severity, status, reportedReleaseId, dueDateMillis, assignee, " +
296
325
  "linkTargets, labels, source, environment, attachments, artifactReference). " +
326
+ "Optional agentTraceability (or flat workflowId/policyFile/…) records CREATED Activity inline — " +
327
+ "prefer this over a separate report-agent-action for issue creates. " +
297
328
  "Authenticated via project API key; project is resolved from the key.",
298
329
  inputSchema: S.createIssueInput,
299
330
  execute: async (args, { postMcp }) => {
@@ -327,6 +358,9 @@ export const TOOL_DEFINITIONS = [
327
358
  body.attachments = a.attachments;
328
359
  if (a.artifactReference != null)
329
360
  body.artifactReference = a.artifactReference;
361
+ const trace = buildAgentTraceabilityPayload(a);
362
+ if (trace)
363
+ body.agentTraceability = trace;
330
364
  return postMcp("/api/mcp/create_issue", body);
331
365
  },
332
366
  },
@@ -837,6 +871,27 @@ export const TOOL_DEFINITIONS = [
837
871
  body.userId = process.env.TESTCHIMP_USER_ID;
838
872
  if (a.branchName)
839
873
  body.branchName = a.branchName;
874
+ // Nested traceability wins for agentModel; only fill from flat/env when nested omits it.
875
+ if (a.traceability && typeof a.traceability === "object") {
876
+ const nested = { ...a.traceability };
877
+ const nestedModel = nested.agentModel != null && String(nested.agentModel).trim() !== ""
878
+ ? String(nested.agentModel).trim()
879
+ : undefined;
880
+ const flatModel = a.agentModel?.trim() || process.env.TESTCHIMP_AGENT_MODEL?.trim();
881
+ if (nestedModel) {
882
+ nested.agentModel = nestedModel;
883
+ }
884
+ else if (flatModel) {
885
+ nested.agentModel = flatModel;
886
+ }
887
+ body.traceability = nested;
888
+ }
889
+ else {
890
+ const model = a.agentModel?.trim() || process.env.TESTCHIMP_AGENT_MODEL?.trim();
891
+ if (model) {
892
+ body.traceability = { agentModel: model };
893
+ }
894
+ }
840
895
  if (a.test) {
841
896
  body.test = a.test;
842
897
  }
@@ -923,6 +978,21 @@ export const TOOL_DEFINITIONS = [
923
978
  });
924
979
  },
925
980
  },
981
+ {
982
+ kebab: "upsert-plans-support-file",
983
+ description: "Create or update any file under the mapped plans root on the platform by relative path (no git commit/push required). " +
984
+ "Primary use: upload workflow execution plans at knowledge/workflow_plans/<workflow-id>/<workflow_execution_id>.plan.md after the Plan phase. " +
985
+ "filePath is relative to the plans mapped root (leading plans/ is stripped). Under workflow_plans/, filenames are coerced to *.plan.md and stored as WORKFLOW_EXECUTION_PLAN. " +
986
+ "Response includes supportFileId, filePath (canonical), filetype, created. Blocking step before Execute for cloud agents.",
987
+ inputSchema: S.upsertPlansSupportFileInput,
988
+ execute: async (args, { postMcp }) => {
989
+ const a = args;
990
+ return postMcp("/api/mcp/upsert_plans_support_file", {
991
+ filePath: a.filePath,
992
+ content: a.content,
993
+ });
994
+ },
995
+ },
926
996
  {
927
997
  kebab: "list-workflow-catalog",
928
998
  description: "List supported TestChimp workflows with Active / Disabled / Missing Config status for the project.",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@testchimp/cli",
3
- "version": "0.1.22",
4
- "description": "TestChimp CLI and MCP server coverage, plans, EaaS, TrueCoverage (calls /api/mcp/*)",
3
+ "version": "0.1.25",
4
+ "description": "TestChimp CLI and MCP server \u2014 coverage, plans, EaaS, TrueCoverage (calls /api/mcp/*)",
5
5
  "type": "module",
6
6
  "main": "dist/bin/testchimp.js",
7
7
  "types": "dist/bin/testchimp.d.ts",