@amistio/cli 0.1.25 → 0.1.27

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/dist/index.js CHANGED
@@ -1691,6 +1691,7 @@ var appEvaluationFindingResultSchema = z.object({
1691
1691
  proposedPlanTitle: z.string().trim().min(1).max(200).optional(),
1692
1692
  proposedPlanRepoPath: z.string().trim().min(1).max(300).optional(),
1693
1693
  proposedPlanContent: z.string().trim().min(1).max(3e4).optional(),
1694
+ dedupeKey: z.string().trim().min(1).max(240).optional(),
1694
1695
  status: appEvaluationFindingStatusSchema.default("open")
1695
1696
  });
1696
1697
  var appEvaluationScanResultSchema = z.object({
@@ -1736,6 +1737,7 @@ var appEvaluationFindingItemSchema = baseItemSchema.extend({
1736
1737
  verificationPlan: z.array(z.string().trim().min(1).max(300)).min(1),
1737
1738
  proposedLifecycleAction: appEvaluationPlanLifecycleActionSchema.default("none"),
1738
1739
  relatedArtifactIds: z.array(z.string().trim().min(1).max(160)).default([]),
1740
+ dedupeKey: z.string().trim().min(1).max(240).optional(),
1739
1741
  proposedPlanDocumentId: z.string().min(1).optional(),
1740
1742
  implementationWorkItemId: z.string().min(1).optional(),
1741
1743
  reviewNotes: z.string().trim().min(1).optional(),
@@ -5452,6 +5454,68 @@ var canonicalAppEvaluationCategories = /* @__PURE__ */ new Map([
5452
5454
  ["operations", "other"],
5453
5455
  ["ops", "other"]
5454
5456
  ]);
5457
+ var canonicalTestCommandKinds = /* @__PURE__ */ new Map([
5458
+ ["verify", "verify"],
5459
+ ["verification", "verify"],
5460
+ ["wholeapp", "verify"],
5461
+ ["wholeappverification", "verify"],
5462
+ ["full", "verify"],
5463
+ ["fullcheck", "verify"],
5464
+ ["fullchecks", "verify"],
5465
+ ["allcheck", "verify"],
5466
+ ["allchecks", "verify"],
5467
+ ["ci", "verify"],
5468
+ ["continuousintegration", "verify"],
5469
+ ["test", "test"],
5470
+ ["tests", "test"],
5471
+ ["testing", "test"],
5472
+ ["unittest", "test"],
5473
+ ["unittests", "test"],
5474
+ ["integrationtest", "test"],
5475
+ ["integrationtests", "test"],
5476
+ ["e2etest", "test"],
5477
+ ["e2etests", "test"],
5478
+ ["endtoend", "test"],
5479
+ ["endtoendtest", "test"],
5480
+ ["spec", "test"],
5481
+ ["specs", "test"],
5482
+ ["suite", "test"],
5483
+ ["testsuite", "test"],
5484
+ ["jest", "test"],
5485
+ ["vitest", "test"],
5486
+ ["coverage", "coverage"],
5487
+ ["coveragereport", "coverage"],
5488
+ ["lint", "lint"],
5489
+ ["linting", "lint"],
5490
+ ["eslint", "lint"],
5491
+ ["format", "lint"],
5492
+ ["formatting", "lint"],
5493
+ ["style", "lint"],
5494
+ ["quality", "lint"],
5495
+ ["qualitycheck", "lint"],
5496
+ ["staticanalysis", "lint"],
5497
+ ["typecheck", "typecheck"],
5498
+ ["typechecks", "typecheck"],
5499
+ ["typechecking", "typecheck"],
5500
+ ["typecheck", "typecheck"],
5501
+ ["tsc", "typecheck"],
5502
+ ["typescript", "typecheck"],
5503
+ ["build", "build"],
5504
+ ["compile", "build"],
5505
+ ["focused", "focused"],
5506
+ ["focus", "focused"],
5507
+ ["targeted", "focused"],
5508
+ ["scoped", "focused"],
5509
+ ["package", "focused"],
5510
+ ["packaged", "focused"],
5511
+ ["affected", "focused"],
5512
+ ["affectedtests", "focused"],
5513
+ ["touched", "focused"],
5514
+ ["touchedtests", "focused"],
5515
+ ["changed", "focused"],
5516
+ ["changedtests", "focused"],
5517
+ ["other", "focused"]
5518
+ ]);
5455
5519
  var canonicalProjectContextCitationSources = /* @__PURE__ */ new Map([
5456
5520
  ["projectbrain", "projectBrain"],
5457
5521
  ["approvedbrain", "projectBrain"],
@@ -5551,9 +5615,10 @@ function createTestQualityScanPrompt(workItem, context) {
5551
5615
  "## Output Contract",
5552
5616
  "",
5553
5617
  "Print exactly one JSON object between the markers below. The CLI will submit only this structured test scan result back to Amistio.",
5554
- "Accepted command kind values: lint, typecheck, unitTest, integrationTest, e2eTest, coverage, build, verify, other.",
5618
+ "Accepted command kind values: verify, test, coverage, lint, typecheck, build, focused.",
5555
5619
  "Accepted command status values: passed, failed, skipped, missing, blocked.",
5556
5620
  "Accepted finding categories: missingTests, missingCoverage, lowCoverage, failingTests, failingQuality, missingCommand, flakyTests, unverifiedImplementation, testGap, other.",
5621
+ "Omit optional fields when unavailable; do not emit null for optional command summary fields such as exitCode, durationMs, outputExcerpt, commandId, or safePaths.",
5557
5622
  "",
5558
5623
  testQualityStart,
5559
5624
  '{"summary":"Whole-app verification exists, but coverage reporting is missing for one package.","profile":{"testProfileId":"test_profile_detected","repositoryLinkId":"repository_link_placeholder","status":"detected","enabled":true,"detectedPackageManager":"pnpm","packageManagers":["pnpm"],"commands":[{"commandId":"verify","kind":"verify","label":"Whole-app verification","source":"detected","scriptName":"verify","workingDirectory":".","required":true}],"coverageThresholds":{"lines":80},"defaultWholeAppCommandId":"verify","focusedCommandIds":[],"lastDetectedAt":"2026-01-01T00:00:00.000Z"},"commandSummaries":[{"commandId":"verify","kind":"verify","label":"Whole-app verification","status":"passed","exitCode":0,"summary":"The repository verification script completed successfully.","safePaths":["package.json"]}],"coverage":{"status":"missing","thresholds":{"lines":80},"summary":"No coverage report was found."},"findings":[{"title":"Coverage report is missing","category":"missingCoverage","severity":"medium","confidence":"high","summary":"The repository test profile does not produce a coverage summary.","affectedSurfaces":["Test verification"],"evidence":["The scan found a test command but no coverage output."],"safePaths":["package.json"],"suggestedAction":"Add or document a coverage command for the affected package and include it in whole-app verification.","verificationPlan":["Run the new coverage command locally","Confirm coverage appears in the Test panel"],"dedupeKey":"missing-coverage"}],"blockedReasons":[],"redactionState":{"status":"clean","redactedFields":[]},"verificationPlan":["Review generated Test findings","Run the whole-app verification command before implementation handoff"],"warnings":[]}',
@@ -5594,6 +5659,7 @@ function createImplementationTestGatePrompt(workItem) {
5594
5659
  "",
5595
5660
  "Print exactly one JSON object between the markers below. The CLI will submit only this structured gate result back to Amistio.",
5596
5661
  "Accepted outcome values: passed, failed, blocked, overridden.",
5662
+ "Omit optional fields when unavailable; do not emit null for optional command summary fields such as exitCode, durationMs, outputExcerpt, commandId, or safePaths.",
5597
5663
  "",
5598
5664
  implementationTestGateStart,
5599
5665
  '{"outcome":"passed","summary":"Focused checks and whole-app verification passed.","commandSummaries":[{"commandId":"verify","kind":"verify","label":"Whole-app verification","status":"passed","exitCode":0,"summary":"The repository verification script completed successfully.","safePaths":["package.json"]}],"coverage":{"status":"unknown","thresholds":{},"summary":"No coverage threshold was configured for this gate."},"findings":[],"blockedReasons":[],"redactionState":{"status":"clean","redactedFields":[]},"verificationPlan":["Record this gate result before marking implementation complete"],"warnings":[]}',
@@ -5875,9 +5941,10 @@ function createAppEvaluationScanPrompt(workItem, context) {
5875
5941
  "Accepted severity values: info, low, medium, high, critical.",
5876
5942
  "Accepted confidence values: low, medium, high.",
5877
5943
  "Accepted proposedLifecycleAction values: createPlan, updatePlan, markCompleted, markImplemented, markSuperseded, markBlocked, archive, keepActive, none.",
5944
+ "Include a stable dedupeKey for each finding based on the underlying issue identity, not scan time, generated wording, or transient ordering.",
5878
5945
  "",
5879
5946
  appEvaluationStart,
5880
- '{"summary":"The app is generally healthy, but one release-readiness plan needs cleanup and verification evidence should be refreshed.","baselineVersion":"amistio-app-evaluation-v1","findings":[{"title":"Stale release plan should be marked superseded","category":"planCleanup","severity":"low","confidence":"high","summary":"A release plan appears to describe a workflow that has since been replaced by a newer accepted plan.","affectedSurfaces":["docs/plans"],"evidence":["A newer plan references the same scope and status, while the older plan remains proposed."],"suggestedAction":"Prepare a cleanup update that marks the stale plan superseded and links to the newer plan.","verificationPlan":["Review both plan files","Confirm the newer plan is accepted before changing lifecycle state"],"safePaths":["docs/plans/PLAN-example.md"],"proposedLifecycleAction":"markSuperseded","relatedArtifactIds":[]}],"verificationPlan":["Review App Evaluation findings for approval","Run the canonical verify gate before implementing approved actions"]}',
5947
+ '{"summary":"The app is generally healthy, but one release-readiness plan needs cleanup and verification evidence should be refreshed.","baselineVersion":"amistio-app-evaluation-v1","findings":[{"title":"Stale release plan should be marked superseded","category":"planCleanup","severity":"low","confidence":"high","dedupeKey":"plan-cleanup-docs-plans-plan-example-superseded","summary":"A release plan appears to describe a workflow that has since been replaced by a newer accepted plan.","affectedSurfaces":["docs/plans"],"evidence":["A newer plan references the same scope and status, while the older plan remains proposed."],"suggestedAction":"Prepare a cleanup update that marks the stale plan superseded and links to the newer plan.","verificationPlan":["Review both plan files","Confirm the newer plan is accepted before changing lifecycle state"],"safePaths":["docs/plans/PLAN-example.md"],"proposedLifecycleAction":"markSuperseded","relatedArtifactIds":[]}],"verificationPlan":["Review App Evaluation findings for approval","Run the canonical verify gate before implementing approved actions"]}',
5881
5948
  appEvaluationEnd,
5882
5949
  "",
5883
5950
  "Do not put Markdown fences around the markers. Do not implement improvements or cleanup."
@@ -6237,7 +6304,71 @@ function parseTestQualityScanResult(output) {
6237
6304
  }
6238
6305
  const payload = output.slice(start + testQualityStart.length, end).trim();
6239
6306
  const parsed = JSON.parse(stripJsonFence(payload));
6240
- return testQualityScanResultSchema.parse(parsed);
6307
+ return testQualityScanResultSchema.parse(normalizeTestQualityScanResult(parsed));
6308
+ }
6309
+ function normalizeTestQualityScanResult(value) {
6310
+ if (!isObjectRecord(value)) {
6311
+ return value;
6312
+ }
6313
+ const normalized = { ...value };
6314
+ if (isObjectRecord(normalized.profile) && Array.isArray(normalized.profile.commands)) {
6315
+ normalized.profile = {
6316
+ ...normalized.profile,
6317
+ commands: normalized.profile.commands.map(normalizeTestCommandKindObject)
6318
+ };
6319
+ }
6320
+ if (Array.isArray(normalized.commandSummaries)) {
6321
+ normalized.commandSummaries = normalized.commandSummaries.map(normalizeTestCommandSummaryObject);
6322
+ }
6323
+ return normalized;
6324
+ }
6325
+ function normalizeImplementationTestGateResult(value) {
6326
+ if (!isObjectRecord(value)) {
6327
+ return value;
6328
+ }
6329
+ const normalized = { ...value };
6330
+ if (Array.isArray(normalized.commandSummaries)) {
6331
+ normalized.commandSummaries = normalized.commandSummaries.map(normalizeTestCommandSummaryObject);
6332
+ }
6333
+ return normalized;
6334
+ }
6335
+ function normalizeTestCommandSummaryObject(value) {
6336
+ if (!isObjectRecord(value)) {
6337
+ return value;
6338
+ }
6339
+ const normalized = { ...value, kind: normalizeTestCommandKind(value.kind) };
6340
+ for (const key of ["commandId", "durationMs", "exitCode", "outputExcerpt", "safePaths"]) {
6341
+ if (normalized[key] === null) {
6342
+ delete normalized[key];
6343
+ }
6344
+ }
6345
+ return normalized;
6346
+ }
6347
+ function normalizeTestCommandKindObject(value) {
6348
+ if (!isObjectRecord(value)) {
6349
+ return value;
6350
+ }
6351
+ return { ...value, kind: normalizeTestCommandKind(value.kind) };
6352
+ }
6353
+ function normalizeTestCommandKind(value) {
6354
+ if (typeof value !== "string") {
6355
+ return value;
6356
+ }
6357
+ const trimmed = value.trim();
6358
+ if (!trimmed) {
6359
+ return value;
6360
+ }
6361
+ const direct = canonicalTestCommandKinds.get(normalizeEnumKey(trimmed));
6362
+ if (direct) {
6363
+ return direct;
6364
+ }
6365
+ for (const segment of trimmed.split(/[\/,|]+/)) {
6366
+ const segmentKind = canonicalTestCommandKinds.get(normalizeEnumKey(segment));
6367
+ if (segmentKind) {
6368
+ return segmentKind;
6369
+ }
6370
+ }
6371
+ return "focused";
6241
6372
  }
6242
6373
  function parseImplementationTestGateResult(output) {
6243
6374
  const start = output.indexOf(implementationTestGateStart);
@@ -6247,7 +6378,7 @@ function parseImplementationTestGateResult(output) {
6247
6378
  }
6248
6379
  const payload = output.slice(start + implementationTestGateStart.length, end).trim();
6249
6380
  const parsed = JSON.parse(stripJsonFence(payload));
6250
- return implementationTestGateResultSchema.parse(parsed);
6381
+ return implementationTestGateResultSchema.parse(normalizeImplementationTestGateResult(parsed));
6251
6382
  }
6252
6383
  function projectContextRefreshSubmissionFailureSummary(result) {
6253
6384
  if (result.refresh.status !== "failed" && result.workItem.status !== "failed") {