claude-memory-admin 1.11.2 → 1.12.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-memory-admin",
3
- "version": "1.11.2",
3
+ "version": "1.12.0",
4
4
  "description": "Browse, audit and prune the auto memory Claude Code keeps under ~/.claude/projects",
5
5
  "keywords": [
6
6
  "claude",
@@ -64,15 +64,16 @@ function picker(options, current, onPick) {
64
64
 
65
65
  for (const option of all) {
66
66
  control.append(node('option', {
67
- value: option.value === null ? '' : option.value,
67
+ value: option.value === null ? '' : String(option.value),
68
68
  text: optionText(option),
69
69
  }));
70
70
  }
71
- control.value = current === null || current === undefined ? '' : current;
71
+ control.value = current === null || current === undefined ? '' : String(current);
72
72
 
73
73
  control.addEventListener('change', () => {
74
74
  control.disabled = true;
75
- onPick(control.value === '' ? null : control.value);
75
+ const picked = all.find((option) => option.value !== null && String(option.value) === control.value);
76
+ onPick(picked ? picked.value : null);
76
77
  });
77
78
  return control;
78
79
  }
@@ -143,6 +144,7 @@ function settingCard(entry, writable) {
143
144
  text: entry.effective ? show(entry.effective.value) : 'unset (default)',
144
145
  }),
145
146
  entry.effective ? node('span', { class: ui.scopeBadge(entry.effective.scope), text: entry.effective.scope }) : null,
147
+ entry.offRecommendation ? node('span', { class: ui.badge('warn'), text: `costs tokens - ${entry.recommended} recommended` }) : null,
146
148
  ]));
147
149
  card.append(node('p', { class: ui.noteTight, text: entry.detail }));
148
150
 
@@ -246,7 +248,7 @@ export async function renderCost(container) {
246
248
 
247
249
  container.append(node('p', {
248
250
  class: ui.noteTight,
249
- text: `The two settings that decide what a session costs, and the model each of your agents runs on. This is the one place in the app that writes outside a memory store: changes land in ${data.settings.userFile} and in the files under ${data.agentsDir}. Your CLAUDE.md and the rest of the instruction chain are never touched.`,
251
+ text: `The settings that decide what a session costs, and the model each of your agents runs on. This is the one place in the app that writes outside a memory store: changes land in ${data.settings.userFile} and in the files under ${data.agentsDir}. Your CLAUDE.md and the rest of the instruction chain are never touched.`,
250
252
  }));
251
253
 
252
254
  for (const problem of data.settings.problems) {
package/src/cost.mjs CHANGED
@@ -1,5 +1,5 @@
1
- // The two settings keys that decide what a session costs, and the only two keys
2
- // this tool ever writes.
1
+ // The settings keys that decide what a session costs, and the only keys this
2
+ // tool ever writes.
3
3
  //
4
4
  // Everything else in the app reports; this module changes ~/.claude/settings.json.
5
5
  // That is a deliberate exception, so the surface is kept as narrow as it can be:
@@ -7,7 +7,7 @@
7
7
  // and a hard refusal to rewrite a settings file that did not parse - overwriting
8
8
  // one would silently drop every setting this tool could not read.
9
9
  //
10
- // The two keys:
10
+ // The keys:
11
11
  //
12
12
  // env.CLAUDE_CODE_SUBAGENT_MODEL the model every subagent, agent-team member
13
13
  // and workflow agent runs on. It outranks both
@@ -16,6 +16,9 @@
16
16
  // outputStyle how Claude writes back in the main
17
17
  // conversation. Subagents run their own system
18
18
  // prompt and are untouched by it.
19
+ // promptSuggestionEnabled whether a suggested next prompt is generated
20
+ // after every turn. On by default, and it
21
+ // spends tokens whether anyone uses it or not.
19
22
 
20
23
  import fs from 'node:fs';
21
24
  import path from 'node:path';
@@ -75,6 +78,23 @@ export const COST_KEYS = [
75
78
  { value: 'Learning', label: 'Learning', note: 'longer answers' },
76
79
  ],
77
80
  },
81
+ {
82
+ key: 'promptSuggestion',
83
+ path: ['promptSuggestionEnabled'],
84
+ label: 'promptSuggestionEnabled',
85
+ title: 'Prompt suggestions',
86
+ detail: 'Generates a suggested next prompt after every turn, which reads the conversation again. Mostly cached, but not free, and wasted if nobody accepts the suggestions. Turn it off unless you use them.',
87
+ envVar: null,
88
+ unset: 'Default',
89
+ allowModelId: false,
90
+ custom: null,
91
+ recommended: false,
92
+ options: [
93
+ { value: null, label: 'Default', note: 'unset - on' },
94
+ { value: false, label: 'false', note: 'saves tokens' },
95
+ { value: true, label: 'true' },
96
+ ],
97
+ },
78
98
  ];
79
99
 
80
100
  /**
@@ -123,6 +143,7 @@ function optionsFor(descriptor, outputStyles) {
123
143
  */
124
144
  export function normaliseCostValue(descriptor, value, outputStyles = []) {
125
145
  if (value === null || value === undefined) return null;
146
+ if (typeof value === 'boolean' && descriptor.options.some((option) => option.value === value)) return value;
126
147
  if (typeof value !== 'string') {
127
148
  throw new Error(`${descriptor.label} takes a string, not ${Array.isArray(value) ? 'a list' : typeof value}.`);
128
149
  }
@@ -224,6 +245,10 @@ export function costReport(options = {}) {
224
245
  shadowedByStronger: Boolean(winner && winner.scope !== 'user'),
225
246
  envVar: descriptor.envVar,
226
247
  envValue,
248
+ recommended: descriptor.recommended,
249
+ // Unset means the built-in default, which for every recommended key is on.
250
+ offRecommendation: descriptor.recommended !== undefined
251
+ && (winner ? winner.value : true) !== descriptor.recommended,
227
252
  };
228
253
  });
229
254