@getpipher/armory-todo 0.5.4 → 0.5.5

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
@@ -221,6 +221,23 @@ Full design + decisions:
221
221
  |---|---|---|
222
222
  | `TODO_DIR` | `~/.pi/agent/todo/` | override the store folder (tests / multiple profiles) |
223
223
 
224
+ `todo.config.json` (in `TODO_DIR`) holds prune ages, health thresholds, and notify toggles. All values are optional — missing fields are merged with defaults on load.
225
+
226
+ ```jsonc
227
+ {
228
+ "version": 1,
229
+ "prune": { "defaultAgeDays": 7, "hardAgeDays": 180, "statuses": ["done", "cancelled"] },
230
+ "health": { "activeMaxOpen": 15, "activeStaleDays": 30, "parkedMax": 10,
231
+ "parkedStaleDays": 60, "archiveMax": 200, "archiveOldDays": 180,
232
+ "perProjectDefaultMax": 8, "maxNotesBytes": 8192 },
233
+ "notify": { "sessionStartCount": true }
234
+ }
235
+ ```
236
+
237
+ | `notify.*` | default | purpose |
238
+ |---|---|---|
239
+ | `sessionStartCount` | `true` | Show the `armory-todo: N open TODOs` startup line. Set `false` to silence it — safety messages (wipe-recovery alert, auto-prune undo info) still surface. |
240
+
224
241
  Run the store tests: `npm test` (315/315 across 11 suites).
225
242
 
226
243
  ## Known issues
@@ -39,7 +39,7 @@ import { healthReport } from "../src/health";
39
39
  import { hardPrune } from "../src/hard-prune";
40
40
  import { TodoPanel } from "../src/panel";
41
41
  import { autoPruneOnSessionStart } from "../src/auto-prune";
42
- import { loadConfig } from "../src/config";
42
+ import { loadConfig, type TodoConfig } from "../src/config";
43
43
  import { projectsOverview } from "../src/projects";
44
44
  import { renameProject } from "../src/registry";
45
45
  import { readAndClearWipeAlert } from "../src/backup";
@@ -90,10 +90,12 @@ export default function (pi: ExtensionAPI) {
90
90
  } catch {
91
91
  // alert optional
92
92
  }
93
+ // One config load reused for the prune age + the notify-suppress flag.
94
+ let cfg: TodoConfig | undefined;
95
+ try { cfg = loadConfig(); } catch { /* config optional */ }
93
96
  let autoMsg = "";
94
- let ageDays = 7;
97
+ let ageDays = cfg?.prune.defaultAgeDays ?? 7;
95
98
  try {
96
- ageDays = loadConfig().prune.defaultAgeDays;
97
99
  const ap = autoPruneOnSessionStart();
98
100
  if (ap) {
99
101
  const lines = ap.items.map((i) => ` [${i.id}] ${i.status} ${i.title}`);
@@ -102,17 +104,27 @@ export default function (pi: ExtensionAPI) {
102
104
  } catch {
103
105
  // auto-prune optional — don't crash the session notify
104
106
  }
107
+ const showCount = cfg?.notify?.sessionStartCount !== false;
105
108
  const open = listTodos();
106
- let msg = `armory-todo: ${open.length} open TODO${open.length === 1 ? "" : "s"}${autoMsg}`;
107
- try {
108
- const report = healthReport();
109
- if (report.flags.length > 0) {
110
- msg += `${autoMsg ? "\n" : " — "}` + `⚠ ${report.flags.length} bloat signal${report.flags.length === 1 ? "" : "s"} (run /todo health)`;
109
+ let msg = "";
110
+ if (showCount) {
111
+ msg = `armory-todo: ${open.length} open TODO${open.length === 1 ? "" : "s"}${autoMsg}`;
112
+ try {
113
+ const report = healthReport();
114
+ if (report.flags.length > 0) {
115
+ msg += `${autoMsg ? "\n" : " — "}` + `⚠ ${report.flags.length} bloat signal${report.flags.length === 1 ? "" : "s"} (run /todo health)`;
116
+ }
117
+ } catch {
118
+ // health check optional
111
119
  }
112
- } catch {
113
- // health check optional
120
+ } else if (autoMsg) {
121
+ // Count line suppressed; still surface the auto-prune undo info.
122
+ msg = `armory-todo${autoMsg}`;
123
+ }
124
+ if (ctx.hasUI) {
125
+ const out = (wipeMsg ? wipeMsg + "\n" : "") + msg;
126
+ if (out) ctx.ui.notify(out, "info");
114
127
  }
115
- if (ctx.hasUI) ctx.ui.notify((wipeMsg ? wipeMsg + "\n" : "") + msg, "info");
116
128
  } catch {
117
129
  // store unavailable — never crash the session
118
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getpipher/armory-todo",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "Global, cross-session TODO for pi \u2014 persists across all sessions and is auto-injected into every prompt. The disk-backed counterpart to branch-scoped pi todo extensions.",
5
5
  "keywords": [
6
6
  "pi-package",
package/src/config.ts CHANGED
@@ -28,10 +28,18 @@ export interface HealthConfig {
28
28
  maxNotesBytes: number; // v0.5.0: per-todo notes byte cap (hard-reject at add/update)
29
29
  }
30
30
 
31
+ export interface NotifyConfig {
32
+ /** Show the `armory-todo: N open TODOs` session-start count line.
33
+ * Safety messages (wipe-recovery alert, auto-prune undo info) still surface
34
+ * when this is false. Default true. */
35
+ sessionStartCount: boolean;
36
+ }
37
+
31
38
  export interface TodoConfig {
32
39
  version: 1;
33
40
  prune: PruneConfig;
34
41
  health: HealthConfig;
42
+ notify: NotifyConfig;
35
43
  }
36
44
 
37
45
  export const DEFAULT_CONFIG: TodoConfig = {
@@ -51,6 +59,9 @@ export const DEFAULT_CONFIG: TodoConfig = {
51
59
  perProjectDefaultMax: 8,
52
60
  maxNotesBytes: 8192,
53
61
  },
62
+ notify: {
63
+ sessionStartCount: true,
64
+ },
54
65
  };
55
66
 
56
67
  /** Deep clone of DEFAULT_CONFIG (so callers can't mutate the constant). */
@@ -77,10 +88,13 @@ export function loadConfig(): TodoConfig {
77
88
  if (health.maxNotesBytes === undefined || typeof health.maxNotesBytes !== "number" || Number.isNaN(health.maxNotesBytes) || health.maxNotesBytes < 0) {
78
89
  health.maxNotesBytes = DEFAULT_CONFIG.health.maxNotesBytes;
79
90
  }
91
+ const notify = { ...DEFAULT_CONFIG.notify, ...(parsed.notify ?? {}) };
92
+ if (typeof notify.sessionStartCount !== "boolean") notify.sessionStartCount = true;
80
93
  return {
81
94
  version: 1,
82
95
  prune: { ...DEFAULT_CONFIG.prune, ...parsed.prune },
83
96
  health,
97
+ notify,
84
98
  };
85
99
  } catch {
86
100
  try {