@widnyana/design-thinking 0.0.5 → 0.0.6

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
@@ -61,6 +61,7 @@ pi -e ./pi-packages/design-thinking
61
61
  |---|---|
62
62
  | `/dt` | Toggle Design Thinking mode. While on, plans and reviews render as Design Graphs. Persists across restarts. |
63
63
  | `/dt on\|off\|status` | Set or query the mode explicitly. |
64
+ | `/dt approve\|deny` | Arm/revoke file edits for the next agent run — run `approve` after a presented graph to let the implementation run edit, `deny` to re-lock. |
64
65
  | `/dt <prompt>` | Turn the mode **on** (never off), then run `<prompt>` under it — graph and clarifying questions first, implementation after your go-ahead. |
65
66
  | `/cg <module \| task>` | Generate a call graph: extract the graph existing code implements, or sketch one for a task. |
66
67
  | `/cg-plan <task>` | Design before code — full Design Graph, then implement to match it. |
@@ -15,6 +15,7 @@
15
15
  * /dt toggle Design Thinking mode
16
16
  * /dt on|off set explicitly
17
17
  * /dt status show current state
18
+ * /dt approve|deny arm/revoke file edits for the next agent run
18
19
  * /dt <prompt> turn mode ON (never off), then run <prompt> as a user
19
20
  * message — graph + clarifying questions before implementation
20
21
  *
@@ -42,7 +43,7 @@ const REF_DIR = path.resolve(
42
43
  "references",
43
44
  );
44
45
 
45
- /** Compact distilled prompt block injected while active (~33 lines). */
46
+ /** Compact distilled prompt block injected while active. */
46
47
  const DISTILLED = `
47
48
  DESIGN THINKING MODE — active.
48
49
  Read the problem. Draw the data flow as a call graph. Write code that IS the graph.
@@ -65,7 +66,9 @@ Rules:
65
66
  refactor — the model does NOT get to reclassify the request): render the
66
67
  Design Graph in Graph Protocol form and any clarifying questions FIRST;
67
68
  ZERO file edits until the user approves the design. Reading/exploring code
68
- first is fine; the FIRST edit is not allowed before the graph.
69
+ first is fine; the FIRST edit is not allowed before the graph. Once the
70
+ user runs /dt approve, edits are armed for the NEXT run: implement the
71
+ approved design without re-presenting the graph.
69
72
  - Design, plan, and review answers must render a Design Graph — fixed
70
73
  sections: PROBLEM, SHAPES, GRAPH, CARDINALITY, BOUNDARIES, BEHAVIOR, SCOPE,
71
74
  TEST LAYERS, VERDICT.
@@ -82,16 +85,18 @@ Skills load BY NAME into the agent (/skill:<name>); the files above are named
82
85
  by stem, NOT by skill name. Exact mapping:
83
86
  /skill:graph-protocol → protocol.md /skill:design-method → method.md
84
87
  /skill:design-graph → design-graph.md
85
- Zero file edits are possible until the user runs /dt approve for the turn —
86
- the extension blocks write/edit tools mechanically. Present the graph first.
88
+ The extension blocks write/edit tools mechanically until the user runs
89
+ /dt approve — it arms the NEXT run, cleared when that run ends. Re-approve
90
+ per implementation round. Present the graph first.
87
91
  NEVER read references/<skill-name>.md — no such files exist.
88
92
  `.trim();
89
93
 
94
+ // pi's file-edit tools — the mechanical gate's scope ("file edits"). Bash
95
+ // stays open for read-only exploration. apply_patch/multiedit are Claude Code
96
+ // tool names that never fire in pi; keep this list to real pi mutators.
90
97
  const MUTATING_TOOLS: Record<string, true> = {
91
98
  write: true,
92
99
  edit: true,
93
- apply_patch: true,
94
- multiedit: true,
95
100
  };
96
101
 
97
102
  interface DtState {
@@ -99,12 +104,13 @@ interface DtState {
99
104
  }
100
105
 
101
106
  const GATE_REASON =
102
- "Design Thinking mode is ON: present the Design Graph (Graph Protocol) and wait for user approval before file edits. The user can unlock this turn with /dt approve.";
107
+ "Design Thinking mode is ON: present the Design Graph (Graph Protocol) and wait for user approval before file edits. The user arms the NEXT run with /dt approve; the approval clears when that run ends.";
103
108
 
104
109
  export default function designThinkingExtension(pi: ExtensionAPI) {
105
110
  let enabled = false;
106
- // Per-turn approval flag: set by /dt approve, reset on every user turn.
107
- let approvedForTurn = false;
111
+ // Armed by /dt approve for the NEXT agent run. Cleared when that run ends
112
+ // (agent_end), by /dt deny, or when the mode turns off. Not persisted.
113
+ let editsApproved = false;
108
114
 
109
115
  function applyStatus(ctx: ExtensionContext) {
110
116
  ctx.ui.setStatus(
@@ -143,28 +149,34 @@ export default function designThinkingExtension(pi: ExtensionAPI) {
143
149
  ctx.ui.setStatus("design-thinking", undefined);
144
150
  });
145
151
 
146
- // /dt — the Design Thinking tool. Toggles mode, or /dt on|off|status.
152
+ // /dt — the Design Thinking tool. Toggles mode; on|off|status set/query;
153
+ // approve|deny arm/revoke file edits; anything else runs as a prompt with mode on.
147
154
  pi.registerCommand("dt", {
148
- description: "Design Thinking mode: /dt toggles, on|off|status set/query, approve|deny unlock/lock file edits for this turn, anything else runs as a prompt with mode on",
155
+ description: "Design Thinking mode: /dt toggles, on|off|status set/query, approve arms the next run for file edits, deny revokes; anything else runs as a prompt with mode on",
149
156
  handler: async (args, ctx) => {
150
157
  const arg = (args ?? "").trim();
151
158
  const lower = arg.toLowerCase();
152
159
 
153
160
  if (lower === "status") {
154
- ctx.ui.notify(`Design Thinking mode: ${enabled ? "on" : "off"}${approvedForTurn ? " (edits approved for this turn)" : ""}`, "info");
161
+ ctx.ui.notify(`Design Thinking mode: ${enabled ? "on" : "off"}${editsApproved ? " (file edits armed for the next run)" : ""}`, "info");
155
162
  return;
156
163
  }
157
164
 
158
- // /dt approve|deny — explicit user unlock/lock for the CURRENT turn.
159
165
  if (lower === "approve") {
160
- approvedForTurn = enabled;
161
- ctx.ui.notify(
162
- enabled ? "Design Thinking: file edits approved for this turn" : "Design Thinking is OFF — nothing to approve",
163
- "info",
164
- );
166
+ if (!enabled) {
167
+ ctx.ui.notify("Design Thinking is OFF — nothing to approve. Run /dt on first.", "info");
168
+ return;
169
+ }
170
+ editsApproved = true;
171
+ ctx.ui.notify("Design Thinking: file edits armed (current or next run) — it may implement the approved design without re-presenting the graph", "info");
172
+ return;
165
173
  }
166
174
  if (lower === "deny") {
167
- approvedForTurn = false;
175
+ if (!editsApproved) {
176
+ ctx.ui.notify("Design Thinking: no approval in effect — file edits are already blocked", "info");
177
+ return;
178
+ }
179
+ editsApproved = false;
168
180
  ctx.ui.notify("Design Thinking: file edits blocked again", "info");
169
181
  return;
170
182
  }
@@ -173,7 +185,7 @@ export default function designThinkingExtension(pi: ExtensionAPI) {
173
185
  // mode and always turns the mode ON (never toggles it off); bare /dt toggles.
174
186
  const prompt = /^(on|off|status)$/.test(lower) ? "" : arg;
175
187
  enabled = lower === "on" || prompt ? true : lower === "off" ? false : !enabled;
176
- if (!enabled) approvedForTurn = false;
188
+ if (!enabled) editsApproved = false;
177
189
  persist();
178
190
  applyStatus(ctx);
179
191
  ctx.ui.notify(
@@ -193,22 +205,25 @@ export default function designThinkingExtension(pi: ExtensionAPI) {
193
205
  },
194
206
  });
195
207
 
196
- // While active, append the distilled block to the system prompt every turn.
208
+ // While active, append the distilled block to the system prompt every run.
197
209
  pi.on("before_agent_start", async (event) => {
198
- // A new user turn starts a fresh agent run: the approval from the
199
- // previous turn does not carry over.
200
- approvedForTurn = false;
201
210
  if (!enabled) return undefined;
202
211
  return {
203
212
  systemPrompt: event.systemPrompt + "\n\n" + DISTILLED + "\n",
204
213
  };
205
214
  });
206
215
 
207
- // Hard gate: while enabled, mutating tools are blocked until the user
208
- // approves the design for this turn (/dt approve). Prompt-level rules
209
- // alone proved insufficient — this is the mechanical backstop.
216
+ // An approved run consumes the approval: clear it when the run ends so
217
+ // later runs are gated again until the user re-approves with /dt approve.
218
+ pi.on("agent_end", async () => {
219
+ editsApproved = false;
220
+ });
221
+
222
+ // Hard gate: while enabled, file-edit tools are blocked until the user
223
+ // arms the next run with /dt approve. Prompt-level rules alone proved
224
+ // insufficient — this is the mechanical backstop.
210
225
  pi.on("tool_call", async (event) => {
211
- if (!enabled || approvedForTurn) return undefined;
226
+ if (!enabled || editsApproved) return undefined;
212
227
  if (!MUTATING_TOOLS[event.toolName]) return undefined;
213
228
  return { block: true, reason: GATE_REASON };
214
229
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@widnyana/design-thinking",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "type": "module",
5
5
  "description": "Design Thinking · Design Graph · Graph Protocol — a stack-agnostic design methodology for pi. Turns every plan, review, and refactor into an annotated call graph. Method originally by r17x; generalized to a pi package by widnyana.",
6
6
  "author": {