@amistio/cli 0.1.17 → 0.1.18

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 CHANGED
@@ -51,6 +51,8 @@ Runner setup and local-tool execution use bounded failure controls. `amistio run
51
51
 
52
52
  Watch mode prints a completed-work success once per work item, keeps fresh completion visible briefly, and returns old completed work to the ready state when no queued, running, blocked, failed, review, or runner-readiness action needs attention.
53
53
 
54
+ Known validation failures such as `unsafe_context_path` are printed with attention-needed next steps. For project-context refresh path-safety failures, deploy the latest web/API fix, update and restart the runner when applicable, retry the refresh, and capture only bounded non-secret output if it repeats.
55
+
54
56
  For headless startup after login on supported user-level service managers:
55
57
 
56
58
  ```sh
package/dist/index.js CHANGED
@@ -1583,6 +1583,73 @@ function decideSyncState(state) {
1583
1583
  }
1584
1584
 
1585
1585
  // ../shared/src/next-action.ts
1586
+ var workFailureGuidanceCodes = ["unsafe_context_path", "unsafe_context_result", "invalid_context_result", "context_map_too_large", "context_map_store_failed"];
1587
+ var projectContextFailureGuidance = {
1588
+ unsafe_context_path: {
1589
+ code: "unsafe_context_path",
1590
+ title: "Attention needed",
1591
+ message: "Project context refresh was rejected because a returned path looked unsafe.",
1592
+ steps: [
1593
+ "Deploy the latest web/API fix and update the local runner if this started after a path-safety release.",
1594
+ "Retry the project context refresh.",
1595
+ "If it fails again, capture the failing repo-relative path or bounded runner output without sharing secrets."
1596
+ ]
1597
+ },
1598
+ unsafe_context_result: {
1599
+ code: "unsafe_context_result",
1600
+ title: "Attention needed",
1601
+ message: "Project context refresh was rejected because the result looked like it contained unsafe evidence.",
1602
+ steps: [
1603
+ "Review the local runner output for accidental secret-looking evidence without pasting secrets into Amistio.",
1604
+ "Retry the project context refresh after removing or narrowing unsafe evidence.",
1605
+ "If it repeats, capture a bounded redacted summary of the runner output."
1606
+ ]
1607
+ },
1608
+ invalid_context_result: {
1609
+ code: "invalid_context_result",
1610
+ title: "Attention needed",
1611
+ message: "Project context refresh returned structured data the server could not accept.",
1612
+ steps: [
1613
+ "Update and restart the local runner so it uses the latest context refresh schema.",
1614
+ "Retry the project context refresh.",
1615
+ "If it fails again, capture the bounded marker-delimited result without source dumps or secrets."
1616
+ ]
1617
+ },
1618
+ context_map_too_large: {
1619
+ code: "context_map_too_large",
1620
+ title: "Attention needed",
1621
+ message: "Project context refresh produced a map too large to store safely.",
1622
+ steps: [
1623
+ "Retry the refresh after narrowing the context scope or waiting for smaller incremental refresh support.",
1624
+ "Keep raw source and large dumps out of the context result.",
1625
+ "If this repeats on normal output, split the context-map storage model before retrying large repositories."
1626
+ ]
1627
+ },
1628
+ context_map_store_failed: {
1629
+ code: "context_map_store_failed",
1630
+ title: "Attention needed",
1631
+ message: "Project context refresh could not be stored safely after validation.",
1632
+ steps: [
1633
+ "Retry the project context refresh once.",
1634
+ "If it repeats, check the web/API storage logs for the safe rejection reason.",
1635
+ "Keep the runner output bounded and avoid sharing raw source or secrets."
1636
+ ]
1637
+ }
1638
+ };
1639
+ function getWorkFailureGuidance(input) {
1640
+ const normalizedMessage = (input.message ?? "").toLowerCase();
1641
+ const code = workFailureGuidanceCodes.find((candidate) => normalizedMessage.includes(candidate));
1642
+ if (!code) {
1643
+ return void 0;
1644
+ }
1645
+ if (input.workKind && input.workKind !== "projectContextRefresh" && !normalizedMessage.includes("project context")) {
1646
+ return void 0;
1647
+ }
1648
+ return projectContextFailureGuidance[code];
1649
+ }
1650
+ function formatWorkFailureGuidanceDetail(guidance) {
1651
+ return `Next steps: ${guidance.steps.join(" ")}`;
1652
+ }
1586
1653
  var nextActionRunnerHeartbeatFreshMs = 15 * 60 * 1e3;
1587
1654
  var nextActionCompletedWorkFreshMs = 60 * 60 * 1e3;
1588
1655
  function computeProjectNextAction(input) {
@@ -1647,11 +1714,11 @@ function computeProjectNextAction(input) {
1647
1714
  }
1648
1715
  const failedBrainGeneration = latestWorkItem(input.workItems.filter((item) => item.workKind === "brainGeneration" && item.status === "failed"));
1649
1716
  if (failedBrainGeneration) {
1650
- return workAction(failedBrainGeneration, "brainGenerationFailed", "user", "danger", "Brain generation failed", failedBrainGeneration.lastStatusMessage ?? "Retry generation after checking the runner output.");
1717
+ return failedWorkAction(failedBrainGeneration, "brainGenerationFailed", "Brain generation failed", failedBrainGeneration.lastStatusMessage ?? "Retry generation after checking the runner output.");
1651
1718
  }
1652
1719
  const failedPlanRevision = latestWorkItem(input.workItems.filter((item) => item.workKind === "planRevision" && item.status === "failed"));
1653
1720
  if (failedPlanRevision) {
1654
- return workAction(failedPlanRevision, "planRevisionFailed", "user", "danger", "Plan revision failed", failedPlanRevision.lastStatusMessage ?? "Review the conversation and request another revision if needed.");
1721
+ return failedWorkAction(failedPlanRevision, "planRevisionFailed", "Plan revision failed", failedPlanRevision.lastStatusMessage ?? "Review the conversation and request another revision if needed.");
1655
1722
  }
1656
1723
  const blockedWork = latestWorkItem(input.workItems.filter((item) => item.status === "blocked" || item.status === "changesRequested"));
1657
1724
  if (blockedWork) {
@@ -1659,7 +1726,7 @@ function computeProjectNextAction(input) {
1659
1726
  }
1660
1727
  const failedWork = latestWorkItem(input.workItems.filter((item) => item.status === "failed"));
1661
1728
  if (failedWork) {
1662
- return workAction(failedWork, "workFailed", "user", "danger", "Work failed", failedWork.lastStatusMessage ?? "Review the failure and retry or update the plan.");
1729
+ return failedWorkAction(failedWork, "workFailed", "Work failed", failedWork.lastStatusMessage ?? "Review the failure and retry or update the plan.");
1663
1730
  }
1664
1731
  const queuedBrainGeneration = latestWorkItem(input.workItems.filter((item) => item.workKind === "brainGeneration" && item.status === "approved"));
1665
1732
  const queuedPlanRevision = latestWorkItem(input.workItems.filter((item) => item.workKind === "planRevision" && item.status === "approved"));
@@ -1698,7 +1765,7 @@ function computeProjectNextAction(input) {
1698
1765
  };
1699
1766
  }
1700
1767
  function formatProjectNextAction(action) {
1701
- return `${action.title}: ${action.message}`;
1768
+ return `${action.title}: ${action.message}${action.detail ? ` ${action.detail}` : ""}`;
1702
1769
  }
1703
1770
  function runnerWaitAction(readiness, fallbackTitle) {
1704
1771
  const repositoryName = readiness.repositoryLink?.repoName ?? "the paired repository";
@@ -1761,13 +1828,21 @@ function isGeneratedDocument(document) {
1761
1828
  const generatedDraftId = document.frontmatter.generatedDraftId;
1762
1829
  return typeof generatedDraftId === "string" && generatedDraftId.length > 0;
1763
1830
  }
1764
- function workAction(workItem, kind, actor, tone, title, message) {
1831
+ function failedWorkAction(workItem, kind, fallbackTitle, fallbackMessage) {
1832
+ const guidance = getWorkFailureGuidance({ message: workItem.lastStatusMessage, workKind: workItem.workKind });
1833
+ if (guidance) {
1834
+ return workAction(workItem, kind, "user", "danger", guidance.title, guidance.message, formatWorkFailureGuidanceDetail(guidance));
1835
+ }
1836
+ return workAction(workItem, kind, "user", "danger", fallbackTitle, fallbackMessage);
1837
+ }
1838
+ function workAction(workItem, kind, actor, tone, title, message, detail) {
1765
1839
  return {
1766
1840
  kind,
1767
1841
  actor,
1768
1842
  tone,
1769
1843
  title,
1770
1844
  message,
1845
+ ...detail ? { detail } : {},
1771
1846
  workItemId: workItem.workItemId,
1772
1847
  ...workItem.claimedByRunnerId ? { runnerId: workItem.claimedByRunnerId } : {},
1773
1848
  updatedAt: workItem.lastStatusAt
@@ -4974,7 +5049,9 @@ function projectContextRefreshSubmissionFailureSummary(result) {
4974
5049
  if (result.refresh.status !== "failed" && result.workItem.status !== "failed") {
4975
5050
  return void 0;
4976
5051
  }
4977
- return result.refresh.error ?? result.workItem.lastStatusMessage ?? "Server rejected the project context refresh result.";
5052
+ const summary = result.refresh.error ?? result.workItem.lastStatusMessage ?? "Server rejected the project context refresh result.";
5053
+ const guidance = getWorkFailureGuidance({ message: summary, workKind: "projectContextRefresh" });
5054
+ return guidance ? `${summary} ${formatWorkFailureGuidanceDetail(guidance)}` : summary;
4978
5055
  }
4979
5056
  function createBrainGenerationPrompt(workItem) {
4980
5057
  const wish = workItem.sourceWish ?? workItem.title;