saving-token 1.0.0 → 1.2.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/README.md CHANGED
@@ -6,6 +6,9 @@ unchanged.
6
6
 
7
7
  Inspired by [karpathy-guidelines](https://github.com/multica-ai/andrej-karpathy-skills).
8
8
 
9
+ The writer is used only when the host model is stronger; otherwise the host
10
+ works directly.
11
+
9
12
  ## Install
10
13
 
11
14
  ### Interactive setup
@@ -42,10 +45,21 @@ After publication, run:
42
45
  npx saving-token@latest install --agent codex
43
46
  ```
44
47
 
45
- The wrapper supports `install --agent codex` and keeps the interactive menus.
48
+ The wrapper supports `install --agent codex` and `update-models --agent codex`.
46
49
  Use the Bash script directly for `--target`, `--model`, `--reasoning-effort`,
47
50
  or `--yes`.
48
51
 
52
+ To choose a new writer model in an existing Codex installation, run:
53
+
54
+ ```bash
55
+ npx saving-token@latest update-models --agent codex
56
+ ```
57
+
58
+ Use **Up/Down** and **Enter** to choose the model. It updates the model list
59
+ and only the writer's model field; it preserves the reasoning effort and shows
60
+ no platform, effort, or confirmation menus. Use the Bash script with
61
+ `--update-models --target claude` or `cursor` for those platforms.
62
+
49
63
  ### Installed paths
50
64
 
51
65
  | Platform | Skill | Writer configuration |
@@ -8,11 +8,11 @@ const args = process.argv.slice(2);
8
8
 
9
9
  if (
10
10
  args.length !== 3 ||
11
- args[0] !== 'install' ||
11
+ !['install', 'update-models'].includes(args[0]) ||
12
12
  args[1] !== '--agent' ||
13
13
  args[2] !== 'codex'
14
14
  ) {
15
- console.error('Usage: saving-token install --agent codex');
15
+ console.error('Usage: saving-token <install|update-models> --agent codex');
16
16
  process.exit(1);
17
17
  }
18
18
 
@@ -24,7 +24,12 @@ const setupPath = path.join(
24
24
  'scripts',
25
25
  'setup.sh'
26
26
  );
27
- const result = spawnSync('bash', [setupPath, '--target', 'codex'], {
27
+ const setupArgs = [setupPath, '--target', 'codex'];
28
+ if (args[0] === 'update-models') {
29
+ setupArgs.push('--update-models');
30
+ }
31
+
32
+ const result = spawnSync('bash', setupArgs, {
28
33
  stdio: 'inherit'
29
34
  });
30
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saving-token",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "bin": {
5
5
  "saving-token": "bin/saving-token.cjs"
6
6
  },
@@ -18,18 +18,25 @@ If your identity is `saving-token-writer` or `saving-token:saving-token-writer`,
18
18
  - If a writable native writer or independent model configuration is unavailable, report instruction-only compatibility and ask before implementing directly.
19
19
  - Configuration is not runtime proof. Check exposed model metadata and disclose mismatches; never silently substitute a model yourself. Claude Code and Cursor may apply host-level fallback.
20
20
 
21
+ ## Model gate
22
+
23
+ - Delegate only when the current host model is stronger than the configured writer model.
24
+ - If the comparison is unknown, do not delegate; the parent completes the task directly under normal authorization.
25
+
21
26
  ## Delegate
22
27
 
23
28
  - Delegate every file write, including edits, deletions, documents, temporary scripts, and formatting.
24
29
  - Give goals and acceptance criteria, not implementation text to paste. Prefer file paths and issue locations over copied source or conversation history.
25
30
  - Batch related changes into one scoped task and reuse the writer for revisions.
26
31
  - The writer follows project rules and authorization boundaries, preserves user edits, implements directly, and runs relevant checks.
32
+ - Put exact focused commands in `Verify`; the writer runs them with the change.
33
+ - For slow E2E or independent confirmation, use a verification-only native subagent. It must not modify files and returns commands, exit codes, result counts when available, and code failures or environmental blockers.
27
34
 
28
35
  ```text
29
36
  Goal: <expected behavior>
30
- Scope: <paths; prohibited changes>
31
- Verify: <acceptance criteria and checks>
32
- Return: changed paths; check results; blockers.
37
+ Scope: <paths; prohibited changes; or verification-only, no file changes>
38
+ Verify: <exact commands>
39
+ Return: changed paths; commands, exit codes, result counts when available; code failures or environmental blockers.
33
40
  ```
34
41
 
35
42
  ## Accept
@@ -12,4 +12,5 @@ disallowedTools:
12
12
  Implement directly. Never delegate or invoke another subagent.
13
13
  Follow project rules and authorization boundaries, and preserve existing user edits.
14
14
  Make only the requested changes and run the requested checks.
15
- Return changed paths, check commands and results, and blockers only.
15
+ For verification-only work, do not modify files.
16
+ Return changed paths; commands, exit codes, result counts when available; and code failures or environmental blockers only.
@@ -7,5 +7,6 @@ developer_instructions = """
7
7
  Implement directly. Do not delegate further.
8
8
  Follow project rules and preserve existing user edits.
9
9
  Run the requested checks.
10
- Return changed paths, check results, and blockers only.
10
+ For verification-only work, do not modify files.
11
+ Return changed paths; commands, exit codes, result counts when available; and code failures or environmental blockers only.
11
12
  """
@@ -11,4 +11,5 @@ is_background: false
11
11
  Implement directly. Never delegate or invoke another subagent.
12
12
  Follow project rules and authorization boundaries, and preserve existing user edits.
13
13
  Make only the requested changes and run the requested checks.
14
- Return changed paths, check commands and results, and blockers only.
14
+ For verification-only work, do not modify files.
15
+ Return changed paths; commands, exit codes, result counts when available; and code failures or environmental blockers only.
@@ -90,6 +90,7 @@ usage() {
90
90
  cat <<'HELP'
91
91
  Usage: setup.sh [--target codex|claude|cursor] [--model ID]
92
92
  [--reasoning-effort EFFORT] [--yes]
93
+ setup.sh --update-models --target codex|claude|cursor
93
94
 
94
95
  Use Up/Down and Enter to choose a platform, model, effort, and confirmation.
95
96
  Esc cancels before any files are changed.
@@ -97,6 +98,7 @@ Esc cancels before any files are changed.
97
98
  --model ID Skip the model menu; required without a terminal.
98
99
  --reasoning-effort EFFORT Optional. Omit to use the host's default behavior.
99
100
  --yes Approve installation and displayed replacements.
101
+ --update-models Choose and update the writer model in an installed Skill.
100
102
  -h, --help Show this help.
101
103
 
102
104
  Model suggestions are not an account availability check. Use only models and
@@ -112,6 +114,7 @@ reasoning_effort=''
112
114
  model_was_set=false
113
115
  effort_was_set=false
114
116
  assume_yes=false
117
+ update_models=false
115
118
 
116
119
  while [[ $# -gt 0 ]]; do
117
120
  case "$1" in
@@ -124,12 +127,17 @@ while [[ $# -gt 0 ]]; do
124
127
  esac
125
128
  shift 2 ;;
126
129
  --yes) assume_yes=true; shift ;;
130
+ --update-models) update_models=true; shift ;;
127
131
  -h|--help) usage; exit 0 ;;
128
132
  *) fail "Unknown option: $1" ;;
129
133
  esac
130
134
  done
131
135
 
132
136
  [[ -n "${HOME:-}" ]] || fail 'HOME is not set.'
137
+ if [[ "$update_models" == true ]]; then
138
+ [[ -n "$target" ]] || fail 'Pass --target with --update-models.'
139
+ [[ "$model_was_set" == false && "$effort_was_set" == false && "$assume_yes" == false ]] || fail '--update-models cannot be combined with --model, --reasoning-effort, or --yes.'
140
+ fi
133
141
  if [[ -z "$target" ]]; then
134
142
  [[ -t 0 ]] || fail 'Pass --target in non-interactive use.'
135
143
  if choose_menu 'Choose a platform:' 'Codex|codex' 'Claude Code|claude' 'Cursor|cursor'; then
@@ -145,30 +153,134 @@ case "$target" in
145
153
  skill_target="$codex_home/skills/saving-token"
146
154
  agent_dir="$codex_home/agents"
147
155
  agent_file='saving-token-writer.toml'
148
- models=(gpt-5.6-luna gpt-5.6-terra gpt-5.3-codex-spark)
156
+ models=(gpt-6-luna gpt-6-sol gpt-6-astra)
149
157
  ;;
150
158
  claude)
151
159
  skill_target="$HOME/.claude/skills/saving-token"
152
160
  agent_dir="$HOME/.claude/agents"
153
161
  agent_file='saving-token-writer.md'
154
- models=(haiku sonnet opus)
162
+ models=(claude-haiku-4-5-20251001 claude-sonnet-5 claude-opus-5-5 claude-fable-5-1)
155
163
  ;;
156
164
  cursor)
157
165
  skill_target="$HOME/.cursor/skills/saving-token"
158
166
  agent_dir="$HOME/.cursor/agents"
159
167
  agent_file='saving-token-writer.md'
160
- models=(composer-2.5 gpt-5.6-sol)
168
+ models=(composer-2.5 gpt-5.6-luna gpt-5.6-terra gpt-5.6-sol claude-sonnet-5 claude-opus-5-5 claude-fable-5-1)
161
169
  ;;
162
170
  *) fail "Unsupported target '$target'. Expected codex, claude, or cursor." ;;
163
171
  esac
164
172
 
165
- if [[ "$model_was_set" != true ]]; then
166
- [[ -t 0 ]] || fail 'Pass --model in non-interactive use.'
173
+ agent_target="$agent_dir/$agent_file"
174
+
175
+ choose_writer_model() {
176
+ local prompt=$1
177
+ local -a model_options
178
+ local model
179
+
167
180
  model_options=()
168
181
  for model in "${models[@]}"; do model_options[${#model_options[@]}]="$model|$model"; done
169
- if choose_menu 'Choose a writer model:' "${model_options[@]}"; then
182
+ if choose_menu "$prompt" "${model_options[@]}"; then
170
183
  writer_model=$MENU_RESULT
184
+ return 0
185
+ fi
186
+ return 1
187
+ }
188
+
189
+ update_installed_model_suggestions() {
190
+ local installed_setup temporary_setup model_line
191
+
192
+ installed_setup="$skill_target/scripts/setup.sh"
193
+ [[ -f "$installed_setup" ]] || fail "No installed Skill script found at $installed_setup. Run install first."
194
+
195
+ model_line=" models=(${models[*]})"
196
+
197
+ temporary_setup="$(mktemp "$(dirname -- "$installed_setup")/.saving-token-setup.XXXXXX")"
198
+ cp -p "$installed_setup" "$temporary_setup"
199
+ if ! awk -v target="$target" -v model_line="$model_line" '
200
+ $0 == " " target ")" { in_target = 1; print; next }
201
+ in_target && $0 == " ;;" { in_target = 0; print; next }
202
+ in_target && $0 ~ /^ models=\([^)]*\)$/ {
203
+ replacements++
204
+ print model_line
205
+ next
206
+ }
207
+ { print }
208
+ END { exit replacements == 1 ? 0 : 1 }
209
+ ' "$installed_setup" > "$temporary_setup"; then
210
+ rm -f "$temporary_setup"
211
+ fail "Could not find one model list for $target in $installed_setup. Run install to refresh the Skill."
212
+ fi
213
+ if ! bash -n "$temporary_setup"; then
214
+ rm -f "$temporary_setup"
215
+ fail 'Updated Skill script failed syntax validation.'
216
+ fi
217
+ if cmp -s "$installed_setup" "$temporary_setup"; then
218
+ rm -f "$temporary_setup"
219
+ printf 'Model suggestions for %s are already current.\n' "$target"
220
+ return
221
+ fi
222
+
223
+ mv -f "$temporary_setup" "$installed_setup"
224
+ printf 'Updated model suggestions for %s in %s.\n' "$target" "$installed_setup"
225
+ }
226
+
227
+ update_writer_model() {
228
+ local temporary_agent model_line cursor_effort line
229
+
230
+ [[ -f "$agent_target" ]] || fail "No writer configuration found at $agent_target. Run install first."
231
+ if [[ "$target" == codex ]]; then
232
+ model_line="model = \"$writer_model\""
171
233
  else
234
+ cursor_effort=''
235
+ if [[ "$target" == cursor ]]; then
236
+ while IFS= read -r line || [[ -n "$line" ]]; do
237
+ if [[ "$line" =~ ^model:\ \"[^\"]*(\[effort=[^]]+\])\"$ ]]; then
238
+ cursor_effort=${BASH_REMATCH[1]}
239
+ break
240
+ fi
241
+ done < "$agent_target"
242
+ fi
243
+ model_line="model: \"$writer_model$cursor_effort\""
244
+ fi
245
+
246
+ temporary_agent="$(mktemp "$(dirname -- "$agent_target")/.${agent_file}.XXXXXX")"
247
+ cp -p "$agent_target" "$temporary_agent"
248
+ if ! awk -v target="$target" -v model_line="$model_line" '
249
+ (target == "codex" && $0 ~ /^model = "[^"]*"$/) ||
250
+ (target != "codex" && $0 ~ /^model: "[^"]*"$/) {
251
+ replacements++
252
+ print model_line
253
+ next
254
+ }
255
+ { print }
256
+ END { exit replacements == 1 ? 0 : 1 }
257
+ ' "$agent_target" > "$temporary_agent"; then
258
+ rm -f "$temporary_agent"
259
+ fail "Could not find one model field in $agent_target. Run install to refresh the writer configuration."
260
+ fi
261
+ if cmp -s "$agent_target" "$temporary_agent"; then
262
+ rm -f "$temporary_agent"
263
+ printf 'Writer model for %s is already %s.\n' "$target" "$writer_model"
264
+ return
265
+ fi
266
+
267
+ mv -f "$temporary_agent" "$agent_target"
268
+ printf 'Updated writer model for %s to %s.\n' "$target" "$writer_model"
269
+ }
270
+
271
+ if [[ "$update_models" == true ]]; then
272
+ [[ -t 0 ]] || fail '--update-models requires a terminal to choose a writer model.'
273
+ if ! choose_writer_model 'Choose a writer model to update:'; then
274
+ cancel_install
275
+ fi
276
+ update_installed_model_suggestions
277
+ update_writer_model
278
+ exit 0
279
+ fi
280
+
281
+ if [[ "$model_was_set" != true ]]; then
282
+ [[ -t 0 ]] || fail 'Pass --model in non-interactive use.'
283
+ if ! choose_writer_model 'Choose a writer model:'; then
172
284
  cancel_install
173
285
  fi
174
286
  fi
@@ -210,7 +322,6 @@ if [[ "$target" == claude ]]; then
210
322
  fi
211
323
 
212
324
  template_path="$SKILL_SOURCE/assets/$target/$agent_file.template"
213
- agent_target="$agent_dir/$agent_file"
214
325
  distributed_files=(SKILL.md scripts/setup.sh assets/codex/saving-token-writer.toml.template assets/claude/saving-token-writer.md.template assets/cursor/saving-token-writer.md.template)
215
326
  for file in "${distributed_files[@]}"; do
216
327
  [[ -f "$SKILL_SOURCE/$file" ]] || fail "Missing required Skill file: $SKILL_SOURCE/$file"