zames_pro 2.75.6 → 2.76.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/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.76.0] - 2026-10-16
11
+
12
+ ### Added
13
+
14
+ - bake methodology skills in, localize skill hints, fix Ctrl+Del and scroll-to-bottom
15
+
10
16
  ## [2.75.6] - 2026-10-16
11
17
 
12
18
  ### Added
package/dist/context.js CHANGED
@@ -57,6 +57,105 @@ const BUILTIN_SKILLS = [
57
57
  'couplings, and any WHY-comments that matter.\n' +
58
58
  '4. Do NOT change code. Answer in the operator language.',
59
59
  },
60
+ // Methodology skills, ported from superpowers (github.com/obra/superpowers)
61
+ // as plain prompt bodies — the zames equivalent of its SessionStart
62
+ // bootstrap, without a hook. The model is nudged to read the matching one
63
+ // before a non-trivial task by SKILLS_DISCIPLINE (src/system-prompt.ts).
64
+ // Baked in (not a file on disk) so a user who installed the npm package has
65
+ // them out of the box; a project skill of the same name overrides them.
66
+ {
67
+ name: 'brainstorming',
68
+ description: 'Use when the request is a GOAL, not a spec — "add X", "make it better", "integrate Y" — and it is unclear what "done" means.',
69
+ body: 'When a request is a goal ("make scrolling feel right"), building ' +
70
+ 'immediately produces the wrong thing fast. First make the intent concrete.\n' +
71
+ 'Pin down: (a) the REAL outcome — what should be TRUE after that is not ' +
72
+ 'true now; (b) the acceptance check — how the operator will know it works; ' +
73
+ '(c) scope edges — what is explicitly NOT part of this; (d) the ' +
74
+ 'alternatives considered and why you chose one.\n' +
75
+ 'zames has NO conversational turn: the operator sees only your final ' +
76
+ 'respond. So do the brainstorming YOURSELF and return a SHORT, concrete ' +
77
+ 'proposal in ONE respond — the goal as you understood it, your ' +
78
+ 'assumptions and defaults, what you will NOT do — then either proceed if ' +
79
+ 'the request was clearly actionable, or stop and ask the ONE decision you ' +
80
+ 'genuinely cannot make alone. For an already-precise request ("read X", ' +
81
+ '"rename Y") skip this entirely.',
82
+ },
83
+ {
84
+ name: 'writing-plans',
85
+ description: 'Use when a task needs more than one or two tool calls — a multi-file change, a new feature, a refactor. Breaks it into small ordered steps with exact paths and a verification for each.',
86
+ body: 'A plan is a sequence of steps a careful engineer with NO project ' +
87
+ 'context could follow. Each step (2-5 minutes) names: the EXACT file ' +
88
+ 'path(s); the concrete edit; how to verify it (command, test name, ' +
89
+ 'expected output). Order matters: put the step that DE-RISKS the task ' +
90
+ 'first (a spike, a failing test, a proof the API works) — do not build ' +
91
+ 'three layers on an unverified assumption.\n' +
92
+ 'Rules: one concern per step ("add the flag AND refactor the caller" is ' +
93
+ 'two); prefer a step that FAILS LOUDLY over one that silently ' +
94
+ 'half-works; every behavioural change gets a test step (see ' +
95
+ 'test-driven-development); if a step turns out wrong, STOP and revise the ' +
96
+ 'plan instead of improvising; a 30-step plan means the task should be ' +
97
+ 'split. In zames the plan lives in your reasoning and, for a long task, ' +
98
+ 'in a TodoWrite list — one entry per step. Do not narrate it between tool ' +
99
+ 'calls; the todo list IS the visible plan.',
100
+ },
101
+ {
102
+ name: 'test-driven-development',
103
+ description: 'Use when writing or changing testable behaviour — a bug fix, a new function, a parser, a formatter. Write the failing test first, watch it fail, then make it pass.',
104
+ body: 'RED -> GREEN -> REFACTOR. The order is the point, not a formality.\n' +
105
+ '1. RED — write the smallest test that expresses the new behaviour and ' +
106
+ 'RUN it. It must FAIL for the RIGHT reason ("not implemented", not a ' +
107
+ 'typo). A test you never saw fail proves nothing.\n' +
108
+ '2. GREEN — write the MINIMUM code that makes it pass; do not add the ' +
109
+ 'next feature "while you are there".\n' +
110
+ '3. REFACTOR — clean up with the test green, then re-run.\n' +
111
+ 'A good test asserts BEHAVIOUR (input -> output), is deterministic (no ' +
112
+ 'sleeps, no network, no wall-clock or test-order dependence) and fails ' +
113
+ 'for ONE reason with a message that says what broke. In this project a ' +
114
+ 'bug fix ALWAYS gets a regression test reproducing the original bug. ' +
115
+ 'When a test needs fixing, ask whether the TEST or the CODE was wrong; ' +
116
+ 'if the code was written before its test, rewrite it driven by the test.',
117
+ },
118
+ {
119
+ name: 'systematic-debugging',
120
+ description: 'Use when something is broken and the cause is not obvious — a failing test, a wrong result, a hang, a crash. Four phases: reproduce, isolate, hypothesize, fix.',
121
+ body: 'Do NOT start by editing code. Work the four phases in order; each ' +
122
+ 'produces an artifact you can point at.\n' +
123
+ '1. REPRODUCE — get a command that FAILS the way the operator describes; ' +
124
+ 'copy the exact error. If it passes you do not have the bug yet: narrow ' +
125
+ 'the input until it fails.\n' +
126
+ '2. ISOLATE — shrink to the smallest failing unit (bisect, stub, ' +
127
+ 'binary-search). Read the code the failing path ACTUALLY executes. Check ' +
128
+ 'the obvious first: wrong file, stale build, cached state, different ' +
129
+ 'config, an error swallowed by a catch.\n' +
130
+ '3. HYPOTHESIZE — state it in one sentence and predict what you should ' +
131
+ 'see if it is right; test exactly that. One change at a time; prefer an ' +
132
+ 'observation (log, test assertion) over an edit. If the prediction is ' +
133
+ 'wrong, DISCARD the hypothesis.\n' +
134
+ '4. FIX AND VERIFY — fix the CAUSE, not the symptom; add a regression ' +
135
+ 'test that fails WITHOUT the fix; re-run the phase-1 reproduction ' +
136
+ 'verbatim; look for the same bug elsewhere.\n' +
137
+ 'Anti-patterns: editing before reproducing; "it works now" without ' +
138
+ 'knowing what changed; silencing an error you do not understand with a ' +
139
+ 'try/catch; trusting a green test never seen red.',
140
+ },
141
+ {
142
+ name: 'verification-before-completion',
143
+ description: 'Use BEFORE declaring a task done — a feature, a bug fix, a generated file. Forces you to run the verification you promised instead of trusting the code looks right.',
144
+ body: '"It should work" is not done. Before reporting success, produce ' +
145
+ 'EVIDENCE from the real artifact, not from your intent.\n' +
146
+ '1. Re-read the original request; tick every requirement (including the ' +
147
+ 'ones in a parenthetical) against something you can show.\n' +
148
+ '2. Run the thing: build/typecheck/tests for code; run a script; for a ' +
149
+ 'generated file, open/parse it and confirm it is COMPLETE, not ' +
150
+ 'truncated; for a UI, the real screen, not the diff.\n' +
151
+ '3. Re-read your own diff as a reviewer: leftover debug output, dead ' +
152
+ 'code, a wrong path, a test that asserts nothing.\n' +
153
+ '4. State the evidence in the final report — the exact command and its ' +
154
+ 'result — so the operator can reproduce it. "Tests pass" without the ' +
155
+ 'command is not evidence.\n' +
156
+ 'If you cannot run the verification, SAY SO explicitly and describe what ' +
157
+ 'you did instead; never report "done" implying a check you did not run.',
158
+ },
60
159
  ];
61
160
  // Per-file budgets. AGENTS.md/MEMORY.md are hand-maintained and grow over
62
161
  // time, so the caps are generous: an AGENTS.md of a real project (this repo's
package/dist/i18n/help.js CHANGED
@@ -574,4 +574,50 @@ export const helpMessages = {
574
574
  ru: 'Индикаторы в статус-строке: 🧠 — глубокое размышление, 🌐 — поиск в интернете (видны, когда включены).',
575
575
  en: 'Status-line icons: 🧠 — Deep thinking, 🌐 — web search (shown when enabled).',
576
576
  },
577
+ // Localized descriptions for the WELL-KNOWN skills (built-in + bundled
578
+ // methodology). A skill's SKILL.md frontmatter is agent-facing English, so
579
+ // showing it verbatim in the «/» hints would leave an English line in a
580
+ // Russian UI. Keyed by skill NAME, applied regardless of source, so a local
581
+ // `.zames/skills/` copy of a bundled skill still shows the translated text.
582
+ // An unknown (user-authored) skill has no key and keeps its own description.
583
+ 'skill.desc.commit': {
584
+ ru: 'подготовить аккуратный git-коммит из текущих изменений',
585
+ en: 'prepare a clean git commit from the current changes',
586
+ },
587
+ 'skill.desc.review': {
588
+ ru: 'ревью текущего диффа на баги и риски (без правок)',
589
+ en: 'review the current diff for bugs and risks (no changes)',
590
+ },
591
+ 'skill.desc.test': {
592
+ ru: 'прогнать тесты проекта и чинить падения до зелёного',
593
+ en: 'run the project tests and fix failures until green',
594
+ },
595
+ 'skill.desc.debug': {
596
+ ru: 'системно диагностировать и починить баг',
597
+ en: 'systematically diagnose and fix a bug',
598
+ },
599
+ 'skill.desc.explain': {
600
+ ru: 'объяснить, как работает файл/модуль/фича',
601
+ en: 'explain how a file/module/feature works',
602
+ },
603
+ 'skill.desc.brainstorming': {
604
+ ru: 'когда запрос — это цель, а не спека: сначала прояснить замысел',
605
+ en: 'when the request is a goal, not a spec: pin down the intent first',
606
+ },
607
+ 'skill.desc.writing-plans': {
608
+ ru: 'разбить многошаговую задачу на маленькие шаги с проверкой каждого',
609
+ en: 'break a multi-step task into small steps, each with a check',
610
+ },
611
+ 'skill.desc.test-driven-development': {
612
+ ru: 'сначала падающий тест, потом код (RED → GREEN → REFACTOR)',
613
+ en: 'write the failing test first, then the code (RED → GREEN → REFACTOR)',
614
+ },
615
+ 'skill.desc.systematic-debugging': {
616
+ ru: 'четыре фазы отладки: воспроизвести, изолировать, гипотеза, фикс',
617
+ en: 'four debugging phases: reproduce, isolate, hypothesize, fix',
618
+ },
619
+ 'skill.desc.verification-before-completion': {
620
+ ru: 'прогнать проверку ПЕРЕД тем, как объявить задачу готовой',
621
+ en: 'run the verification BEFORE declaring the task done',
622
+ },
577
623
  };
package/dist/index.js CHANGED
@@ -530,9 +530,18 @@ async function refreshDynamicCommands(workdir) {
530
530
  for (const s of skills) {
531
531
  if (!s.userInvokable)
532
532
  continue;
533
+ // A well-known skill (built-in or bundled methodology) has a localized
534
+ // description keyed by NAME — its SKILL.md frontmatter is agent-facing
535
+ // English, which must not leak into a Russian UI. `t` returns the key
536
+ // itself when it is missing, so an unknown (user-authored) skill falls
537
+ // back to its own description.
538
+ const descKey = 'skill.desc.' + s.name;
539
+ const localized = t(descKey);
533
540
  out.push({
534
541
  name: '/' + s.name,
535
- description: s.description || t('help.cmd.skill'),
542
+ description: localized !== descKey
543
+ ? localized
544
+ : s.description || t('help.cmd.skill'),
536
545
  });
537
546
  }
538
547
  const cmds = await loadCommands(workdir);
@@ -254,6 +254,10 @@ export class TuiEditor {
254
254
  this.printAbove(theme.userBar('▌ ') +
255
255
  theme.user(wrapToWidth(display, contentWidth() - 2)));
256
256
  this.store.set({ pastes: [] });
257
+ // Sending a message pins the log back to the newest content: the operator
258
+ // expects their message (and the answer) at the BOTTOM, so a viewport left
259
+ // scrolled-up (PgUp / wheel) must snap to scroll=0 on submit.
260
+ this.store.set({ scroll: 0 });
257
261
  this.onSubmit?.(text, atts);
258
262
  if (this.busy)
259
263
  this.thinking();
package/dist/tui/edit.js CHANGED
@@ -82,35 +82,26 @@ export function deleteWordLeft(s) {
82
82
  return { ...s, buf: chars.join(''), cursor: i };
83
83
  }
84
84
  /**
85
- * Delete the word on the RIGHT of the cursor (Ctrl+Delete / Alt+Delete).
86
- *
87
- * FALLBACK: at the END of the line there is no word to the right, so the key
88
- * did NOTHING and the operator (whose terminal sends the standard xterm
89
- * Ctrl+Delete) read it as "Ctrl+Delete does not delete the word before the
90
- * cursor". Deleting the word on the LEFT there matches what other terminal
91
- * editors do and what the operator expects, while keeping the standard
92
- * right-delete when the cursor is mid-line.
85
+ * Delete the word on the RIGHT of the cursor (Ctrl+Delete / Alt+Delete):
86
+ * skip the whitespace after the cursor, then delete up to the end of the next
87
+ * word — the mirror of deleteWordLeft(). At the end of the line there is
88
+ * nothing to the right, so the buffer is left UNCHANGED (never a surprise
89
+ * leftward delete), matching the legacy LineEditor's _deleteWordRight().
93
90
  */
94
91
  export function deleteWordRight(s) {
95
92
  const chars = charsOf(s);
96
- // Nothing to the right (end of buffer or only whitespace to the newline):
97
- // delete the word on the LEFT instead of doing nothing.
98
- let probe = s.cursor;
99
- while (probe < chars.length &&
100
- chars[probe] !== NL &&
101
- /\s/.test(chars[probe])) {
102
- probe++;
103
- }
104
- if (probe >= chars.length || chars[probe] === NL) {
105
- return deleteWordLeft(s);
106
- }
93
+ // Stop at a NEWLINE: it is whitespace for /\s/ but must never be swallowed
94
+ // by a word delete (the old code guarded this; without the guard the key
95
+ // ate the line break).
107
96
  let i = s.cursor;
108
- while (i < chars.length && /\s/.test(chars[i]))
97
+ while (i < chars.length && chars[i] !== NL && /\s/.test(chars[i]))
109
98
  i++;
110
- while (i < chars.length && !/\s/.test(chars[i]))
99
+ while (i < chars.length && chars[i] !== NL && !/\s/.test(chars[i]))
111
100
  i++;
101
+ if (i === s.cursor)
102
+ return s;
112
103
  chars.splice(s.cursor, i - s.cursor);
113
- return { ...s, buf: chars.join('') };
104
+ return { ...s, buf: chars.join(''), cursor: s.cursor };
114
105
  }
115
106
  /** Delete from the cursor to the end of the current LOGICAL line (Ctrl+K). */
116
107
  export function killToLineEnd(s) {
package/dist/tui/keys.js CHANGED
@@ -35,8 +35,8 @@ export function parseCsiU(raw) {
35
35
  if (cp === 13 && (ctrl || alt))
36
36
  return { type: 'newline' };
37
37
  if (cp === 3) {
38
- // Ctrl/Alt+Delete deletes the word on the LEFT (see dispatchKey).
39
- return ctrl || alt ? { type: 'deleteWordLeft' } : { type: 'delete' };
38
+ // Ctrl/Alt+Delete deletes the word on the RIGHT (standard editor binding).
39
+ return ctrl || alt ? { type: 'deleteWordRight' } : { type: 'delete' };
40
40
  }
41
41
  if (cp === 127) {
42
42
  return ctrl || alt ? { type: 'deleteWordLeft' } : { type: 'backspace' };
@@ -85,11 +85,11 @@ export function dispatchKey(input, key, ctx, isVisualEdge) {
85
85
  return { type: 'wordLeft' };
86
86
  if (key.rightArrow)
87
87
  return { type: 'wordRight' };
88
- // Ctrl+Delete deletes the word BEFORE the cursor (the operator's binding:
89
- // "Ctrl+Del must delete the word before the cursor"). Ctrl+Backspace does
90
- // the same. Plain Delete still deletes one char to the RIGHT.
88
+ // Ctrl+Delete deletes the word AFTER the cursor (the standard editor
89
+ // binding, same as the legacy LineEditor). Ctrl+Backspace deletes the word
90
+ // BEFORE it. Plain Delete still deletes one char to the right.
91
91
  if (key.delete)
92
- return { type: 'deleteWordLeft' };
92
+ return { type: 'deleteWordRight' };
93
93
  if (key.backspace)
94
94
  return { type: 'deleteWordLeft' };
95
95
  if (key.home)
@@ -143,16 +143,16 @@ export function dispatchKey(input, key, ctx, isVisualEdge) {
143
143
  if (input === 'f')
144
144
  return { type: 'wordRight' };
145
145
  // VSCode sends Ctrl+Delete as `ESC d` (which Ink reports as Alt+d).
146
- // The operator expects it to delete the word BEFORE the cursor.
146
+ // Standard editor binding: delete the word AFTER the cursor.
147
147
  if (input === 'd')
148
- return { type: 'deleteWordLeft' };
148
+ return { type: 'deleteWordRight' };
149
149
  if (key.backspace)
150
150
  return { type: 'deleteWordLeft' };
151
- // Alt/Ctrl+Delete also deletes the word BEFORE the cursor (the operator's
152
- // binding, consistent with ESC d): some terminals encode Ctrl+Delete as
153
- // meta+Delete rather than ESC d.
151
+ // Alt/Ctrl+Delete also deletes the word AFTER the cursor (consistent with
152
+ // ESC d): some terminals encode Ctrl+Delete as meta+Delete rather than
153
+ // ESC d.
154
154
  if (key.delete)
155
- return { type: 'deleteWordLeft' };
155
+ return { type: 'deleteWordRight' };
156
156
  return null;
157
157
  }
158
158
  // ---- LF as a bare newline (Ctrl+J) ----
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zames_pro",
3
- "version": "2.75.6",
3
+ "version": "2.76.0",
4
4
  "description": "Terminal coding agent that drives a real browser to chat with DeepSeek, Qwen and other web LLMs — no API key required. Reads and edits files, runs commands, commits to git, like Claude Code / Codex CLI.",
5
5
  "type": "module",
6
6
  "bin": {