qatools-cli 1.2.0 → 1.2.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 (2) hide show
  1. package/package.json +1 -1
  2. package/qatools.js +58 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qatools-cli",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "CLI for QA Tools — requirements, epics, sprints, sessions, App Context sync, project agenda. The companion to qa-tools.com.",
5
5
  "scripts": {
6
6
  "release": "npm version patch --no-git-tag-version && npm publish",
package/qatools.js CHANGED
@@ -3190,6 +3190,7 @@ const MCP_INSTRUCTIONS = `qa-tools: requirements-driven QA. Rules that apply to
3190
3190
  - The backlog is signals (bug=AVV, requirement_gap=GAP, technical_defect=DEF, improvement=IMP), not a task list.
3191
3191
  - Backlog flow: open → in_progress → ready_for_test → resolved. Set ready_for_test when you believe a fix is done; resolved needs evidence (min 10 chars) and, except GAP, a prior ready_for_test.
3192
3192
  - Requirement status implemented/tested needs evidence: test output, file:line, expected vs actual, or "no test applies because <reason>".
3193
+ - Sprint planning: plan approved, functional requirements only (update_requirement sprintId), never backlog items; non-functional requirements are continuous and never go into sprints. Gather facts first (list_sprints, sprint_velocity, list_epics, list_requirements), respect epic dependsOn, present the plan as a table (sprint | requirement | reason) and change NOTHING until the user approves it in this conversation. If the user isn't here or wants to decide later, save it with propose_sprint_plan instead — they approve in qa-tools. Full procedure: prompt plan_sprints.
3193
3194
  - Every tool takes an optional projectId; without it the configured project (qatools setup) is used.`;
3194
3195
 
3195
3196
  const mcpStr = (description, extra = {}) => ({ type: "string", description, ...extra });
@@ -3379,6 +3380,59 @@ const mcpTools = [
3379
3380
  };
3380
3381
  },
3381
3382
  },
3383
+ {
3384
+ name: "propose_sprint_plan",
3385
+ description: "Save a sprint plan as a PENDING proposal instead of applying it. A project member reviews it in qa-tools (Sprints → Plan proposals), selects rows and approves — Claude can never approve. Use when the user isn't in this conversation, or asks to decide later. Only approved, functional requirements; each row targets an existing sprintId OR a newSprintRef from newSprints. The whole proposal is refused if any row can't be planned.",
3386
+ inputSchema: mcpSchema({
3387
+ goal: mcpStr("What the plan optimises for, e.g. 'Release 4.0 by Nov 18'"),
3388
+ summary: mcpStr("Short rationale: capacity used, dependency order, risks"),
3389
+ items: {
3390
+ type: "array",
3391
+ description: "One row per requirement",
3392
+ items: {
3393
+ type: "object",
3394
+ properties: {
3395
+ requirementId: mcpStr("Requirement document ID"),
3396
+ sprintId: mcpStr("Existing sprint ID (or use newSprintRef)"),
3397
+ newSprintRef: mcpStr("ref of a sprint in newSprints"),
3398
+ reason: mcpStr("Why this requirement goes in this sprint"),
3399
+ },
3400
+ required: ["requirementId", "reason"],
3401
+ additionalProperties: false,
3402
+ },
3403
+ },
3404
+ newSprints: {
3405
+ type: "array",
3406
+ description: "Sprints to create if the proposal is approved",
3407
+ items: {
3408
+ type: "object",
3409
+ properties: {
3410
+ ref: mcpStr("Your local reference, e.g. new-1"),
3411
+ name: mcpStr("Sprint name"),
3412
+ releaseDate: mcpStr("End date YYYY-MM-DD"),
3413
+ startDate: mcpStr("Start date YYYY-MM-DD"),
3414
+ },
3415
+ required: ["ref", "name", "releaseDate"],
3416
+ additionalProperties: false,
3417
+ },
3418
+ },
3419
+ omitted: {
3420
+ type: "array",
3421
+ description: "Requirements deliberately left out, with why",
3422
+ items: { type: "object", properties: { key: mcpStr("Requirement key"), reason: mcpStr("Why") }, required: ["key", "reason"], additionalProperties: false },
3423
+ },
3424
+ }, ["items"]),
3425
+ run: async (a) => {
3426
+ const r = await mcpCall("createPlanProposal", { projectId: a.projectId, ...mcpPick(a, ["goal", "summary", "items", "newSprints", "omitted"]) });
3427
+ return { ...r, next: "Pending. A project member approves or rejects it in qa-tools under Sprints → Plan proposals." };
3428
+ },
3429
+ },
3430
+ {
3431
+ name: "list_plan_proposals",
3432
+ description: "List sprint-plan proposals and their status (pending/approved/rejected), with who decided and what was applied.",
3433
+ inputSchema: mcpSchema({ status: mcpStr("Filter by status", { enum: ["pending", "approved", "rejected"] }) }),
3434
+ run: async (a) => (await mcpCall("listPlanProposals", { projectId: a.projectId, status: a.status || null })).proposals,
3435
+ },
3382
3436
  {
3383
3437
  name: "get_sprint_items",
3384
3438
  description: "Everything planned in a sprint: its requirements (the planning unit) and the backlog signals linked to it.",
@@ -3523,14 +3577,15 @@ Follow these steps in order:
3523
3577
 
3524
3578
  1. Gather facts, don't guess: list_sprints, sprint_velocity, list_epics, list_requirements (status approved, plus anything already planned in open sprints).
3525
3579
  2. Draft a plan. Only requirements are planned — never create backlog items as tasks. Rules:
3526
- - Only status=approved requirements without a sprint are candidates. Never touch completed sprints or requirements already in one.
3580
+ - Only status=approved, functional requirements without a sprint are candidates. Non-functional (compliance) requirements are continuous — never plan them. Never touch completed sprints or requirements already in one.
3527
3581
  - An epic's requirements never go into an earlier sprint than the requirements of the epics it dependsOn.
3528
3582
  - Order by priority (1 first), then epic priority.
3529
3583
  - Per sprint, plan roughly averageDonePerCompletedSprint requirements (from sprint_velocity), counting what is already planned there. If there is no history, say so and propose a conservative number.
3530
3584
  - If the requirements don't fit in the existing sprints, propose new sprints (name + end date) — don't create them yet.
3531
3585
  3. Present the proposal as a table: sprint | requirement key | title | reason (priority / epic dependency / capacity). Also list what you deliberately left out and why, and any dependency conflicts you found.
3532
- 4. STOP and wait for the user's approval. Change nothing before that. Apply any adjustments the user asks for and show the table again.
3533
- 5. After approval: create_sprint for any new sprints, then update_requirement with sprintId for each planned requirement. Report each change and any refusal verbatim — never retry a refused change in a different way.
3586
+ 4. STOP and ask the user: approve here, or save it as a proposal to decide later in qa-tools? Change nothing before that. Apply any adjustments the user asks for and show the table again.
3587
+ - If nobody is there to answer (an unattended run), or the user chooses "later": call propose_sprint_plan with the same rows, and report the result. Do not apply anything yourself.
3588
+ 5. After approval in this conversation: create_sprint for any new sprints, then update_requirement with sprintId for each planned requirement. Report each change and any refusal verbatim — never retry a refused change in a different way.
3534
3589
  6. End with get_sprint_items for each affected sprint so the user can see the result.`,
3535
3590
  },
3536
3591
  ];