pi-goal-x 0.10.1 → 0.10.2

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
@@ -10,10 +10,10 @@ The extension is designed around one rule: **the user owns intent; the agent exe
10
10
 
11
11
  All core features of [@capyup/pi-goal](https://github.com/capyup/pi-goal) are preserved. The following changes are specific to pi-goal-x:
12
12
 
13
- ### Mid-flight objective updates
13
+ ### Goal objective is immutable
14
14
 
15
- - **`update_goal({updatedObjective})`** the agent can now sync the goal objective mid-flight when user requirements change, *without* completing the goal. This ensures the completion auditor evaluates against the latest requirements. The combined path (`updatedObjective` + `status: "complete"`) applies the update first, then runs the normal completion+audit flow.
16
- - **`apply_goal_tweak`** remains available for `/goal-tweak` drafting revisions; the new parameter is the lightest possible touch on the existing `update_goal` tool.
15
+ - The goal objective is immutable the agent **must not** modify it autonomously. Objective changes are only possible through `apply_goal_tweak`, which is gated behind the user-initiated `/goal-tweak` drafting flow. This prevents the agent from silently changing the goal contract.
16
+ - **`apply_goal_tweak`** is the sole mechanism for updating the objective, available exclusively during a `/goal-tweak` drafting interview. If the user's requirements change, they must run `/goal-tweak` to initiate the revision flow.
17
17
 
18
18
  ### Deferred archival
19
19
 
@@ -106,7 +106,6 @@ import {
106
106
  shouldInjectPostCompactReminder,
107
107
  validateGoalAbort,
108
108
  validateGoalCompletion,
109
- validateGoalUpdate,
110
109
  validatePauseGoal,
111
110
  validateResumeGoal,
112
111
  } from "./goal-policy.ts";
@@ -1707,73 +1706,27 @@ export default function goalExtension(pi: ExtensionAPI): void {
1707
1706
  "Do not call update_goal merely because work is stopping, substantial progress was made, or tests passed without covering every requirement.",
1708
1707
  "Do not use update_goal=complete as an escape hatch when you are blocked. If you are blocked, call pause_goal({reason, suggestedAction?}) instead so the user can intervene.",
1709
1708
  "For sisyphus goals, do not mark complete until every numbered step has been executed and individually verified against its done criterion.",
1710
- "If the user gives requirements, feedback, or corrections that differ from the goal objective, the goal is stale. Use update_goal with updatedObjective to sync the objective before continuing work or before marking the goal complete. This ensures the auditor evaluates against the latest requirements.",
1709
+ "The goal objective is immutable. The agent MUST NOT modify the goal objective on its own initiative. If the user gives requirements, feedback, or corrections that differ from the goal objective, ask the user to run /goal-tweak to revise the goal. Use goal_question to confirm when the change is ambiguous.",
1711
1710
  "If you have just run the test suite successfully and the tests all pass, include a testResults object with the exit code (0) and relevant output. The auditor will see this evidence and can skip re-running the tests.",
1712
1711
  ],
1713
1712
  parameters: Type.Object({
1714
1713
  status: Type.Optional(StringEnum([COMPLETE_STATUS] as const, { description: "Set to complete only when the objective is achieved." })),
1715
1714
  completionSummary: Type.Optional(Type.String({ description: "Concise completion claim and evidence summary passed to the independent auditor agent." })),
1716
1715
  confirmBypassAuditor: Type.Optional(Type.Boolean({ description: "Set to true to confirm bypassing the independent auditor when it is disabled in settings." })),
1717
- updatedObjective: Type.Optional(Type.String({ description: "Revised goal objective. Use when the user's requirements have changed mid-flight. The goal remains active so the agent can continue working toward the new objective. Can be combined with status=complete to update the objective before the completion audit." })),
1716
+
1718
1717
  testResults: Type.Optional(Type.Object({
1719
1718
  exitCode: Type.Number({ description: "Exit code of the test run (0 = success)" }),
1720
1719
  suiteName: Type.Optional(Type.String({ description: "Test suite name, e.g. 'npm test'" })),
1721
1720
  output: Type.Optional(Type.String({ description: "Last lines of test output showing results" })),
1722
1721
  timestamp: Type.Optional(Type.String({ description: "ISO timestamp of when tests were run" })),
1723
1722
  }, { description: "Structured test evidence passed to the auditor so it can skip redundant test re-runs. If you have just run the test suite successfully, include this so the auditor accepts the results without re-running." })),
1724
- }),
1723
+ }, { additionalProperties: false }),
1725
1724
  executionMode: "sequential",
1726
1725
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
1727
1726
  reconcileFocusedGoalFromDisk(ctx);
1728
1727
 
1729
- // -- Phase 1: Objective update (quick sync) --
1730
- // Apply updatedObjective before any completion logic so the completion
1731
- // flow (if status=complete is also set) reads the latest objective.
1732
- if (params.updatedObjective !== undefined) {
1733
- const newObjective = params.updatedObjective.trim();
1734
- if (!newObjective) throw new Error("update_goal requires a non-empty updatedObjective.");
1735
- const updateGate = validateGoalUpdate({ goal: state.goal });
1736
- if (!updateGate.ok) {
1737
- return {
1738
- content: [{ type: "text", text: updateGate.message }],
1739
- details: goalDetails(state.goal),
1740
- };
1741
- }
1742
- if (!state.goal) throw new Error("Goal disappeared during objective update.");
1743
- const next: GoalRecord = {
1744
- ...state.goal,
1745
- objective: newObjective,
1746
- updatedAt: nowIso(),
1747
- };
1748
- state.goal = writeActiveGoalFile(ctx, next);
1749
- pi.appendEntry(STATE_ENTRY, goalDetails(state.goal));
1750
- try {
1751
- appendGoalEvent(ctx, {
1752
- type: "goal_tweaked",
1753
- goalId: state.goal.id,
1754
- changeSummary: "Objective updated via update_goal",
1755
- at: state.goal.updatedAt,
1756
- });
1757
- } catch {
1758
- // Ledger append failure should not block update
1759
- }
1760
- updateUI(ctx);
1761
-
1762
- // Quick sync only (no status=complete) — return without terminating
1763
- if (params.status !== COMPLETE_STATUS) {
1764
- return {
1765
- content: [{ type: "text", text: `Goal objective updated.` }],
1766
- details: goalDetails(state.goal),
1767
- };
1768
- }
1769
- // Fall through: status=complete also set, proceed with completion below
1770
- }
1771
-
1772
1728
  // -- Phase 2: Status validation --
1773
1729
  if (params.status !== COMPLETE_STATUS) {
1774
- if (params.updatedObjective === undefined) {
1775
- throw new Error("update_goal requires either status=complete or updatedObjective.");
1776
- }
1777
1730
  throw new Error("update_goal requires status=complete when marking a goal complete.");
1778
1731
  }
1779
1732
 
@@ -2074,7 +2027,7 @@ export default function goalExtension(pi: ExtensionAPI): void {
2074
2027
  };
2075
2028
  },
2076
2029
  renderCall(args, theme) {
2077
- const label = args?.status ?? args?.updatedObjective ? "sync" : "";
2030
+ const label = args?.status ?? "";
2078
2031
  return new Text(theme.fg("toolTitle", "update_goal ") + theme.fg("success", label), 0, 0);
2079
2032
  },
2080
2033
  renderResult(result, _options, theme) {
@@ -48,7 +48,7 @@ If the user explicitly asks to abandon/cancel this goal, or the objective is obs
48
48
 
49
49
  Do NOT silently invent workarounds, fake completion, or quietly redefine the objective. Do NOT call update_goal=complete to escape a blocker.
50
50
 
51
- Goal evolution: if the user gives requirements, feedback, or corrections that differ from the goal objective, the goal is stale. Propose the updated objective concisely and wait for the user to confirm before continuing. Use update_goal with updatedObjective for narrow focus-area changes, or suggest /goal-tweak for broader revisions (boundaries, constraints, multiple sections). Do NOT mark the goal complete with a stale objective.${sisyphusDisciplineBlock(goal) ? `\n${sisyphusDisciplineBlock(goal)}` : ""}`;
51
+ Goal evolution: if the user gives requirements, feedback, or corrections that differ from the goal objective, the goal is stale. The goal objective is immutable the agent must NOT modify it autonomously. Propose the updated objective concisely and ask the user to run /goal-tweak to revise it. Do NOT mark the goal complete with a stale objective.${sisyphusDisciplineBlock(goal) ? `\n${sisyphusDisciplineBlock(goal)}` : ""}`;
52
52
  }
53
53
 
54
54
  export function continuationPrompt(goal: GoalRecord): string {
@@ -83,7 +83,7 @@ export function continuationPrompt(goal: GoalRecord): string {
83
83
  "Do not call update_goal unless the goal is complete enough to survive independent semantic auditing. Do not mark a goal complete merely because work is stopping.",
84
84
  "Do not ask the user for confirmation unless there is a real blocker.",
85
85
  "",
86
- "Goal evolution: if the user gives requirements, feedback, or corrections that differ from the goal objective, the goal is stale. Propose the updated objective concisely and wait for the user to confirm before continuing. Use update_goal with updatedObjective for narrow focus-area changes, or suggest /goal-tweak for broader revisions (boundaries, constraints, multiple sections). Do NOT mark the goal complete with a stale objective.",
86
+ "Goal evolution: if the user gives requirements, feedback, or corrections that differ from the goal objective, the goal is stale. The goal objective is immutable the agent must NOT modify it autonomously. Propose the updated objective concisely and ask the user to run /goal-tweak to revise it. Do NOT mark the goal complete with a stale objective.",
87
87
  "",
88
88
  "If you hit a real blocker (missing credentials, contradictory spec, file/permission you cannot access, dangerous operation pending user approval, or an unclear Sisyphus-style ordered plan), call pause_goal({reason, suggestedAction?}) and stop. If the user explicitly asks to abandon/cancel, or the objective is obsolete, impossible, or unsafe to continue, call abort_goal({reason}) and stop. Do not silently invent workarounds. Do not fake completion. pause_goal and abort_goal are structured lifecycle exits; update_goal=complete is not an escape hatch for blockers.",
89
89
  ...(goal.sisyphus ? ["", sisyphusDisciplineBlock(goal)] : []),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-goal-x",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
4
4
  "description": "Goal mode extension for pi: persistent long-running objectives, /goal-set drafting, Sisyphus prompt style, autoContinue, and an above-editor status overlay. Fork of @capyup/pi-goal.",
5
5
  "license": "MIT",
6
6
  "author": "pi-goal-x contributors",