zames_pro 2.49.3 → 2.49.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/dist/browser.js +7 -7
- package/dist/config.js +17 -5
- package/dist/i18n.js +60 -0
- package/dist/index.js +2 -1
- package/dist/mcp.js +19 -1
- package/dist/self-review.js +44 -34
- package/dist/sessions.js +9 -2
- package/dist/transcript.js +2 -2
- package/package.json +2 -2
package/dist/browser.js
CHANGED
|
@@ -605,7 +605,7 @@ export class DeepSeekBrowser {
|
|
|
605
605
|
// busy, by a clear error in _launchOnce().
|
|
606
606
|
if (await profileLooksLocked()) {
|
|
607
607
|
if (this.debug)
|
|
608
|
-
console.error('profile:
|
|
608
|
+
console.error('profile: removing Singleton files');
|
|
609
609
|
await cleanSingletonFiles();
|
|
610
610
|
}
|
|
611
611
|
// Headless: if we already know the sanitized UA for THIS engine build, use
|
|
@@ -641,13 +641,13 @@ export class DeepSeekBrowser {
|
|
|
641
641
|
// uses it immediately (no relaunch). Keyed by executable path.
|
|
642
642
|
void writeCachedHeadlessUA(headlessEngineKey(), fixed);
|
|
643
643
|
if (this.debug)
|
|
644
|
-
console.error('profile: headless UA
|
|
644
|
+
console.error('profile: headless UA -> relaunching with a plain Chrome UA');
|
|
645
645
|
await this.context.close().catch(() => { });
|
|
646
646
|
await this._launchOnce();
|
|
647
647
|
}
|
|
648
648
|
catch (e) {
|
|
649
649
|
if (this.debug)
|
|
650
|
-
console.error('profile: UA
|
|
650
|
+
console.error('profile: UA fix failed:', e.message);
|
|
651
651
|
}
|
|
652
652
|
}
|
|
653
653
|
async _launchOnce() {
|
|
@@ -669,7 +669,7 @@ export class DeepSeekBrowser {
|
|
|
669
669
|
catch (e) {
|
|
670
670
|
if (/Target page, context or browser has been closed|profile.*in use/i.test(e.message)) {
|
|
671
671
|
if (this.debug)
|
|
672
|
-
console.error('profile:
|
|
672
|
+
console.error('profile: busy, relaunching after cleanup');
|
|
673
673
|
// Do NOT kill a foreign chrome (see AGENTS.md): only clear the
|
|
674
674
|
// Singleton files and retry. If the profile is genuinely in use by a
|
|
675
675
|
// live browser, nukeProfile() below fails safely and the error
|
|
@@ -680,7 +680,7 @@ export class DeepSeekBrowser {
|
|
|
680
680
|
}
|
|
681
681
|
catch {
|
|
682
682
|
if (this.debug)
|
|
683
|
-
console.error('profile:
|
|
683
|
+
console.error('profile: nuking the profile');
|
|
684
684
|
await nukeProfile();
|
|
685
685
|
this.context = await chromium.launchPersistentContext(USER_DATA_DIR, options);
|
|
686
686
|
}
|
|
@@ -826,7 +826,7 @@ export class DeepSeekBrowser {
|
|
|
826
826
|
// 1) Already signed in (session cookie in the persistent profile)?
|
|
827
827
|
if (await this.isLoggedIn()) {
|
|
828
828
|
if (this.debug)
|
|
829
|
-
console.error('auth:
|
|
829
|
+
console.error('auth: session already active');
|
|
830
830
|
return;
|
|
831
831
|
}
|
|
832
832
|
// 2) Try to sign in automatically with the saved credentials. The
|
|
@@ -906,7 +906,7 @@ export class DeepSeekBrowser {
|
|
|
906
906
|
// Prompt only when we have a login field to fill.
|
|
907
907
|
if (!(await this._loginFormVisible())) {
|
|
908
908
|
if (this.debug)
|
|
909
|
-
console.error('auth:
|
|
909
|
+
console.error('auth: login form not found');
|
|
910
910
|
return false;
|
|
911
911
|
}
|
|
912
912
|
console.log('\n' + theme.warn(this._t('auth.need_login')));
|
package/dist/config.js
CHANGED
|
@@ -4,7 +4,12 @@ import os from 'os';
|
|
|
4
4
|
import { DEFAULT_LOCALE } from './i18n.js';
|
|
5
5
|
const ZAMES_HOME = path.join(os.homedir(), '.zames');
|
|
6
6
|
const HOME_CONFIG = path.join(ZAMES_HOME, 'config.json');
|
|
7
|
-
|
|
7
|
+
// The PROJECT config path is resolved LAZILY: `/cd` changes process.cwd() at
|
|
8
|
+
// runtime, so freezing it at import time meant a `.zamesrc.json` in the new
|
|
9
|
+
// working directory was never read (and writes went to the OLD directory).
|
|
10
|
+
export function projectConfigPath() {
|
|
11
|
+
return path.join(process.cwd(), '.zamesrc.json');
|
|
12
|
+
}
|
|
8
13
|
export const DEFAULTS = {
|
|
9
14
|
maxIterations: 0,
|
|
10
15
|
// Headless by default: the browser runs without a visible window. Set
|
|
@@ -68,7 +73,7 @@ export const DEFAULTS = {
|
|
|
68
73
|
};
|
|
69
74
|
export function loadConfig() {
|
|
70
75
|
const merged = JSON.parse(JSON.stringify(DEFAULTS));
|
|
71
|
-
for (const file of [HOME_CONFIG,
|
|
76
|
+
for (const file of [HOME_CONFIG, projectConfigPath()]) {
|
|
72
77
|
try {
|
|
73
78
|
const data = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
74
79
|
deepMerge(merged, data);
|
|
@@ -76,7 +81,7 @@ export function loadConfig() {
|
|
|
76
81
|
catch (e) {
|
|
77
82
|
const err = e;
|
|
78
83
|
if (err.code !== 'ENOENT') {
|
|
79
|
-
console.error(`config:
|
|
84
|
+
console.error(`config: failed to read ${file}: ${err.message}`);
|
|
80
85
|
}
|
|
81
86
|
}
|
|
82
87
|
}
|
|
@@ -395,7 +400,7 @@ export function validateConfigValue(field, raw) {
|
|
|
395
400
|
return parseConfigValue(field, raw);
|
|
396
401
|
}
|
|
397
402
|
export function configPathFor(scope) {
|
|
398
|
-
return scope === 'project' ?
|
|
403
|
+
return scope === 'project' ? projectConfigPath() : HOME_CONFIG;
|
|
399
404
|
}
|
|
400
405
|
/**
|
|
401
406
|
* Read only the specified config file (without merging with defaults), so that
|
|
@@ -455,5 +460,12 @@ export function resetConfigValue(scope, key) {
|
|
|
455
460
|
fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
456
461
|
return file;
|
|
457
462
|
}
|
|
458
|
-
|
|
463
|
+
// 'PROJECT_CONFIG' stays a getter so existing callers that only DISPLAY the
|
|
464
|
+
// path (help, /config) keep working while still reflecting the current cwd.
|
|
465
|
+
export const CONFIG_PATHS = {
|
|
466
|
+
HOME_CONFIG,
|
|
467
|
+
get PROJECT_CONFIG() {
|
|
468
|
+
return projectConfigPath();
|
|
469
|
+
},
|
|
470
|
+
};
|
|
459
471
|
export { ZAMES_HOME };
|
package/dist/i18n.js
CHANGED
|
@@ -814,6 +814,66 @@ const CATALOG = {
|
|
|
814
814
|
ru: 'Использование: /self-apply <name>',
|
|
815
815
|
en: 'Usage: /self-apply <name>',
|
|
816
816
|
},
|
|
817
|
+
'self.no_src': {
|
|
818
|
+
ru: 'Самообзор отменён: в {dir} нет .ts файлов. Проверь, что src/ не пуст и ты запускаешь агента из корня проекта.',
|
|
819
|
+
en: 'Self-review aborted: no .ts files in {dir}. Check that src/ is not empty and you run the agent from the project root.',
|
|
820
|
+
},
|
|
821
|
+
'self.no_src_err': {
|
|
822
|
+
ru: 'SRC_DIR пуст — нечего ревьюить',
|
|
823
|
+
en: 'SRC_DIR is empty - nothing to review',
|
|
824
|
+
},
|
|
825
|
+
'self.snapshot': { ru: '📸 Снапшот: {dir}', en: '📸 Snapshot: {dir}' },
|
|
826
|
+
'self.files': { ru: 'Файлов: {n} — {list}', en: 'Files: {n} — {list}' },
|
|
827
|
+
'self.starting': {
|
|
828
|
+
ru: 'Начинаю самообзор...',
|
|
829
|
+
en: 'Starting self-review...',
|
|
830
|
+
},
|
|
831
|
+
'self.report': { ru: '📋 Отчёт:', en: '📋 Report:' },
|
|
832
|
+
'self.report_empty': { ru: '(пусто)', en: '(empty)' },
|
|
833
|
+
'self.report_path': { ru: 'Отчёт: {v}', en: 'Report: {v}' },
|
|
834
|
+
'self.snapshot_path': { ru: 'Снапшот: {v}', en: 'Snapshot: {v}' },
|
|
835
|
+
'self.changed': {
|
|
836
|
+
ru: 'Изменено: {n} файл(ов): {list}',
|
|
837
|
+
en: 'Changed: {n} file(s): {list}',
|
|
838
|
+
},
|
|
839
|
+
'self.changed_none': {
|
|
840
|
+
ru: 'Изменено: (ничего — только отчёт)',
|
|
841
|
+
en: 'Changed: (nothing - report only)',
|
|
842
|
+
},
|
|
843
|
+
'self.next': { ru: 'Дальше:', en: 'Next:' },
|
|
844
|
+
'self.diff_hint': {
|
|
845
|
+
ru: ' /self-diff {name} — посмотреть различия',
|
|
846
|
+
en: ' /self-diff {name} — view the diff',
|
|
847
|
+
},
|
|
848
|
+
'self.apply_hint': {
|
|
849
|
+
ru: ' /self-apply {name} — применить к живому src/',
|
|
850
|
+
en: ' /self-apply {name} — apply to the live src/',
|
|
851
|
+
},
|
|
852
|
+
'self.no_diff': { ru: 'Различий нет.', en: 'No differences.' },
|
|
853
|
+
'self.apply_no_ts': {
|
|
854
|
+
ru: 'В снапшоте {dir} нет .ts файлов. Apply отменён, чтобы не стирать src/.',
|
|
855
|
+
en: 'Snapshot {dir} has no .ts files. Apply aborted to avoid wiping src/.',
|
|
856
|
+
},
|
|
857
|
+
'self.applied': {
|
|
858
|
+
ru: '✅ Применено: {n} файл(ов)',
|
|
859
|
+
en: '✅ Applied: {n} file(s)',
|
|
860
|
+
},
|
|
861
|
+
'self.backup': { ru: 'Бэкап: {dir}', en: 'Backup: {dir}' },
|
|
862
|
+
'self.restart_hint': {
|
|
863
|
+
ru: 'Перезапусти агента, чтобы изменения вступили в силу.',
|
|
864
|
+
en: 'Restart the agent for the changes to take effect.',
|
|
865
|
+
},
|
|
866
|
+
'self.no_snapshots': { ru: 'Снапшотов нет.', en: 'No snapshots.' },
|
|
867
|
+
'self.list_title': {
|
|
868
|
+
ru: 'Снапшоты самообзора:',
|
|
869
|
+
en: 'Self-review snapshots:',
|
|
870
|
+
},
|
|
871
|
+
'self.list_changed': { ru: '[{n} изменено]', en: '[{n} changed]' },
|
|
872
|
+
'self.list_unchanged': { ru: '[без правок]', en: '[no changes]' },
|
|
873
|
+
'self.list_commands': {
|
|
874
|
+
ru: 'Команды: /self-diff <name>, /self-apply <name>',
|
|
875
|
+
en: 'Commands: /self-diff <name>, /self-apply <name>',
|
|
876
|
+
},
|
|
817
877
|
'self.fix_hint': {
|
|
818
878
|
ru: '\n💡 Режим ревью по снапшоту {name}. Пиши агенту задачу или /self-done.\n',
|
|
819
879
|
en: '\n💡 Review mode on snapshot {name}. Send the agent a task or /self-done.\n',
|
package/dist/index.js
CHANGED
|
@@ -2149,6 +2149,7 @@ async function main() {
|
|
|
2149
2149
|
config,
|
|
2150
2150
|
focus: focus || undefined,
|
|
2151
2151
|
transcript,
|
|
2152
|
+
locale: currentLocale,
|
|
2152
2153
|
});
|
|
2153
2154
|
// Switch to review mode:
|
|
2154
2155
|
// - working directory = snapshot
|
|
@@ -2262,7 +2263,7 @@ async function main() {
|
|
|
2262
2263
|
}
|
|
2263
2264
|
if (lower === '/self-list') {
|
|
2264
2265
|
try {
|
|
2265
|
-
await mod.selfList({ config });
|
|
2266
|
+
await mod.selfList({ config, locale: currentLocale });
|
|
2266
2267
|
}
|
|
2267
2268
|
catch (e) {
|
|
2268
2269
|
console.error(theme.error(t('msg.error')), e.message);
|
package/dist/mcp.js
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
// The MCP client advertises a name+version to servers. Read the real version
|
|
5
|
+
// from package.json (the previous hardcoded '1.0.0' silently drifted from the
|
|
6
|
+
// package). Best-effort: an unreadable package.json must never break MCP.
|
|
7
|
+
function packageVersion() {
|
|
8
|
+
try {
|
|
9
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(here, '..', 'package.json'), 'utf-8'));
|
|
11
|
+
if (pkg && typeof pkg.version === 'string')
|
|
12
|
+
return pkg.version;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// fall through
|
|
16
|
+
}
|
|
17
|
+
return '0.0.0';
|
|
18
|
+
}
|
|
1
19
|
/** Names of the servers found in a config, before any connection. */
|
|
2
20
|
export async function listConfiguredServers(workdir) {
|
|
3
21
|
const files = await discoverConfigFiles(workdir);
|
|
@@ -226,7 +244,7 @@ export function qualifyToolName(server, tool) {
|
|
|
226
244
|
async function connectServer(name, cfg, debug) {
|
|
227
245
|
try {
|
|
228
246
|
const { Client } = await import('@modelcontextprotocol/sdk/client/index.js');
|
|
229
|
-
const client = new Client({ name: 'zames', version:
|
|
247
|
+
const client = new Client({ name: 'zames', version: packageVersion() }, { capabilities: {} });
|
|
230
248
|
let transport;
|
|
231
249
|
if (cfg.url) {
|
|
232
250
|
if (cfg.transport === 'sse') {
|
package/dist/self-review.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import fs from 'fs/promises';
|
|
3
3
|
import { theme } from './theme.js';
|
|
4
|
+
import { translate, DEFAULT_LOCALE } from './i18n.js';
|
|
4
5
|
import { fileURLToPath } from 'url';
|
|
5
6
|
import { ZAMES_HOME } from './config.js';
|
|
6
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -22,6 +23,12 @@ function resolveSrcDir() {
|
|
|
22
23
|
}
|
|
23
24
|
const SRC_DIR = resolveSrcDir();
|
|
24
25
|
const SNAP_ROOT = path.join(ZAMES_HOME, 'snapshots');
|
|
26
|
+
// Localization for everything the OPERATOR sees. The locale is passed in from
|
|
27
|
+
// the caller (src/index.ts holds currentLocale); without it we fall back to the
|
|
28
|
+
// default so a direct call never breaks.
|
|
29
|
+
function translator(locale) {
|
|
30
|
+
return translate(locale || DEFAULT_LOCALE);
|
|
31
|
+
}
|
|
25
32
|
// Dynamic import of the logic with a timestamp — so that on /reload (or
|
|
26
33
|
// auto-reload) self-review uses FRESH tools/agent-loop, not the ones cached on
|
|
27
34
|
// first load. Otherwise reload wouldn't reach self-review's dependencies.
|
|
@@ -54,7 +61,8 @@ async function copyDirJsFiles(from, to) {
|
|
|
54
61
|
return copied;
|
|
55
62
|
}
|
|
56
63
|
// ---------- /self-review ----------
|
|
57
|
-
export async function selfReview({ browser, focus, transcript, }) {
|
|
64
|
+
export async function selfReview({ browser, focus, transcript, locale, }) {
|
|
65
|
+
const t = translator(locale);
|
|
58
66
|
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
59
67
|
const snapRoot = path.join(SNAP_ROOT);
|
|
60
68
|
const snapDir = path.join(snapRoot, `run-${stamp}`);
|
|
@@ -62,9 +70,8 @@ export async function selfReview({ browser, focus, transcript, }) {
|
|
|
62
70
|
await ensureDir(snapDir);
|
|
63
71
|
const copied = await copyDirJsFiles(SRC_DIR, snapDir);
|
|
64
72
|
if (copied.length === 0) {
|
|
65
|
-
console.error(theme.error(
|
|
66
|
-
|
|
67
|
-
throw new Error('SRC_DIR пуст — нечего ревьюить');
|
|
73
|
+
console.error(theme.error('\n✖ ' + t('self.no_src', { dir: SRC_DIR })));
|
|
74
|
+
throw new Error(t('self.no_src_err'));
|
|
68
75
|
}
|
|
69
76
|
// Copy package.json for context — so the agent sees the dependencies
|
|
70
77
|
try {
|
|
@@ -72,9 +79,9 @@ export async function selfReview({ browser, focus, transcript, }) {
|
|
|
72
79
|
await fs.writeFile(path.join(snapDir, 'package.json'), pkg, 'utf-8');
|
|
73
80
|
}
|
|
74
81
|
catch { }
|
|
75
|
-
console.log(theme.system(
|
|
76
|
-
console.log(theme.system(
|
|
77
|
-
console.log(theme.system('
|
|
82
|
+
console.log(theme.system('\n' + t('self.snapshot', { dir: snapDir })));
|
|
83
|
+
console.log(theme.system(t('self.files', { n: copied.length, list: copied.join(', ') })));
|
|
84
|
+
console.log(theme.system(t('self.starting') + '\n'));
|
|
78
85
|
const taskPrompt = buildReviewPrompt({ focus, snapDir });
|
|
79
86
|
const { createTools, runAgentLoop } = await loadFresh();
|
|
80
87
|
const tools = createTools(snapDir, { undo: null });
|
|
@@ -94,42 +101,43 @@ export async function selfReview({ browser, focus, transcript, }) {
|
|
|
94
101
|
console.log(theme.warn(`🔧 ${name}`), theme.system(preview));
|
|
95
102
|
},
|
|
96
103
|
onToolResult: (r) => {
|
|
97
|
-
const
|
|
98
|
-
console.log(theme.system(` → ${
|
|
104
|
+
const text = typeof r === 'string' ? r : JSON.stringify(r);
|
|
105
|
+
console.log(theme.system(` → ${text.slice(0, 200).replace(/\n/g, ' ↵ ')}\n`));
|
|
99
106
|
},
|
|
100
107
|
onAssistantMessage: (msg) => {
|
|
101
108
|
finalMessage = msg;
|
|
102
|
-
console.log(theme.assistant('\n
|
|
109
|
+
console.log(theme.assistant('\n' + t('self.report') + '\n'));
|
|
103
110
|
console.log(msg);
|
|
104
111
|
console.log();
|
|
105
112
|
},
|
|
106
113
|
});
|
|
107
114
|
// Save the report
|
|
108
115
|
const reportPath = path.join(snapDir, '_report.md');
|
|
109
|
-
await fs.writeFile(reportPath, finalMessage || '
|
|
116
|
+
await fs.writeFile(reportPath, finalMessage || t('self.report_empty'), 'utf-8');
|
|
110
117
|
// Compute what changed
|
|
111
118
|
const changed = await diffFiles(SRC_DIR, snapDir);
|
|
112
119
|
console.log(theme.system('─'.repeat(60)));
|
|
113
|
-
console.log(theme.system(
|
|
114
|
-
console.log(theme.system(
|
|
120
|
+
console.log(theme.system(t('self.report_path', { v: reportPath })));
|
|
121
|
+
console.log(theme.system(t('self.snapshot_path', { v: snapDir })));
|
|
115
122
|
if (changed.length) {
|
|
116
|
-
console.log(theme.assistant(
|
|
123
|
+
console.log(theme.assistant(t('self.changed', { n: changed.length, list: changed.join(', ') })));
|
|
117
124
|
}
|
|
118
125
|
else {
|
|
119
|
-
console.log(theme.system(
|
|
126
|
+
console.log(theme.system(t('self.changed_none')));
|
|
120
127
|
}
|
|
121
|
-
console.log(theme.user(
|
|
122
|
-
console.log(theme.user(
|
|
123
|
-
console.log(theme.user(
|
|
128
|
+
console.log(theme.user('\n' + t('self.next')));
|
|
129
|
+
console.log(theme.user(t('self.diff_hint', { name: path.basename(snapDir) })));
|
|
130
|
+
console.log(theme.user(t('self.apply_hint', { name: path.basename(snapDir) })));
|
|
124
131
|
console.log();
|
|
125
132
|
return { snapDir, reportPath, changed };
|
|
126
133
|
}
|
|
127
134
|
// ---------- /self-diff ----------
|
|
128
|
-
export async function selfDiff({ name, }) {
|
|
135
|
+
export async function selfDiff({ name, locale, }) {
|
|
136
|
+
const t = translator(locale);
|
|
129
137
|
const snapDir = path.join(SNAP_ROOT, name);
|
|
130
138
|
const snapStat = await fs.stat(snapDir).catch(() => null);
|
|
131
139
|
if (!snapStat)
|
|
132
|
-
throw new Error(
|
|
140
|
+
throw new Error(t('self.snapshot_not_found', { dir: snapDir }));
|
|
133
141
|
const { unifiedDiff, colorDiff } = await import('./diff.js');
|
|
134
142
|
const files = await fs.readdir(snapDir);
|
|
135
143
|
let anyDiff = false;
|
|
@@ -150,15 +158,16 @@ export async function selfDiff({ name, }) {
|
|
|
150
158
|
console.log(colorDiff(diff));
|
|
151
159
|
}
|
|
152
160
|
if (!anyDiff) {
|
|
153
|
-
console.log(theme.system('
|
|
161
|
+
console.log(theme.system(t('self.no_diff')));
|
|
154
162
|
}
|
|
155
163
|
}
|
|
156
164
|
// ---------- /self-apply ----------
|
|
157
|
-
export async function selfApply({ name, }) {
|
|
165
|
+
export async function selfApply({ name, locale, }) {
|
|
166
|
+
const t = translator(locale);
|
|
158
167
|
const snapDir = path.join(SNAP_ROOT, name);
|
|
159
168
|
const snapStat = await fs.stat(snapDir).catch(() => null);
|
|
160
169
|
if (!snapStat)
|
|
161
|
-
throw new Error(
|
|
170
|
+
throw new Error(t('self.snapshot_not_found', { dir: snapDir }));
|
|
162
171
|
// Back up the current src before overwriting
|
|
163
172
|
const stamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
164
173
|
const backupDir = path.join(SNAP_ROOT, `backup-before-apply-${stamp}`);
|
|
@@ -166,7 +175,7 @@ export async function selfApply({ name, }) {
|
|
|
166
175
|
const files = await fs.readdir(snapDir);
|
|
167
176
|
const jsFiles = files.filter((f) => f.endsWith('.ts'));
|
|
168
177
|
if (jsFiles.length === 0) {
|
|
169
|
-
throw new Error(
|
|
178
|
+
throw new Error(t('self.apply_no_ts', { dir: snapDir }));
|
|
170
179
|
}
|
|
171
180
|
const applied = [];
|
|
172
181
|
for (const f of jsFiles) {
|
|
@@ -174,28 +183,29 @@ export async function selfApply({ name, }) {
|
|
|
174
183
|
await fs.writeFile(path.join(SRC_DIR, f), data, 'utf-8');
|
|
175
184
|
applied.push(f);
|
|
176
185
|
}
|
|
177
|
-
console.log(theme.assistant(
|
|
186
|
+
console.log(theme.assistant('\n' + t('self.applied', { n: applied.length })));
|
|
178
187
|
console.log(theme.system(applied.join(', ')));
|
|
179
|
-
console.log(theme.system(
|
|
180
|
-
console.log(theme.warn(
|
|
188
|
+
console.log(theme.system(t('self.backup', { dir: backupDir })));
|
|
189
|
+
console.log(theme.warn('\n' + t('self.restart_hint') + '\n'));
|
|
181
190
|
}
|
|
182
191
|
// ---------- /self-list ----------
|
|
183
|
-
export async function selfList({
|
|
192
|
+
export async function selfList({ locale, } = {}) {
|
|
193
|
+
const t = translator(locale);
|
|
184
194
|
const snapRoot = path.join(SNAP_ROOT);
|
|
185
195
|
let entries;
|
|
186
196
|
try {
|
|
187
197
|
entries = await fs.readdir(snapRoot);
|
|
188
198
|
}
|
|
189
199
|
catch {
|
|
190
|
-
console.log(theme.system('
|
|
200
|
+
console.log(theme.system(t('self.no_snapshots')));
|
|
191
201
|
return;
|
|
192
202
|
}
|
|
193
203
|
if (!entries.length) {
|
|
194
|
-
console.log(theme.system('
|
|
204
|
+
console.log(theme.system(t('self.no_snapshots')));
|
|
195
205
|
return;
|
|
196
206
|
}
|
|
197
207
|
entries.sort();
|
|
198
|
-
console.log(theme.system('
|
|
208
|
+
console.log(theme.system(t('self.list_title')));
|
|
199
209
|
for (const e of entries) {
|
|
200
210
|
const full = path.join(snapRoot, e);
|
|
201
211
|
const stat = await fs.stat(full).catch(() => null);
|
|
@@ -208,13 +218,13 @@ export async function selfList({ config: _config, } = {}) {
|
|
|
208
218
|
.catch(() => false);
|
|
209
219
|
const changedCount = (await diffFiles(SRC_DIR, full)).length;
|
|
210
220
|
const tag = changedCount
|
|
211
|
-
? theme.assistant(
|
|
212
|
-
: theme.system('
|
|
221
|
+
? theme.assistant(t('self.list_changed', { n: changedCount }))
|
|
222
|
+
: theme.system(t('self.list_unchanged'));
|
|
213
223
|
const rep = hasReport ? theme.user('📋') : ' ';
|
|
214
224
|
console.log(` ${rep} ${e} ${tag}`);
|
|
215
225
|
}
|
|
216
226
|
console.log();
|
|
217
|
-
console.log(theme.system('
|
|
227
|
+
console.log(theme.system(t('self.list_commands') + '\n'));
|
|
218
228
|
}
|
|
219
229
|
// ---------- helpers ----------
|
|
220
230
|
async function diffFiles(origDir, newDir) {
|
package/dist/sessions.js
CHANGED
|
@@ -7,6 +7,12 @@ import os from 'os';
|
|
|
7
7
|
// opened session for a specific working directory.
|
|
8
8
|
const SESSIONS_DIR = path.join(os.homedir(), '.zames', '.sessions');
|
|
9
9
|
const INDEX_FILE = path.join(SESSIONS_DIR, 'last.json');
|
|
10
|
+
export const SESSIONS_FORMAT_VERSION = 1;
|
|
11
|
+
function atomicWriteJson(file, value) {
|
|
12
|
+
const tmp = file + '.tmp-' + process.pid;
|
|
13
|
+
fs.writeFileSync(tmp, JSON.stringify(value, null, 2), 'utf-8');
|
|
14
|
+
fs.renameSync(tmp, file);
|
|
15
|
+
}
|
|
10
16
|
function ensureDir() {
|
|
11
17
|
fs.mkdirSync(SESSIONS_DIR, { recursive: true });
|
|
12
18
|
}
|
|
@@ -33,13 +39,14 @@ export function saveSession({ id, title = '', workdir = '', todos, }) {
|
|
|
33
39
|
workdir: workdir || prev.workdir || '',
|
|
34
40
|
createdAt: prev.createdAt || now,
|
|
35
41
|
updatedAt: now,
|
|
42
|
+
version: SESSIONS_FORMAT_VERSION,
|
|
36
43
|
};
|
|
37
44
|
// Keep the previous checklist unless a new one is explicitly passed —
|
|
38
45
|
// saveLastChat() calls this for title/workdir only and must not wipe it.
|
|
39
46
|
const nextTodos = todos !== undefined ? todos : prev.todos;
|
|
40
47
|
if (nextTodos !== undefined)
|
|
41
48
|
data.todos = nextTodos;
|
|
42
|
-
|
|
49
|
+
atomicWriteJson(file, data);
|
|
43
50
|
writeIndex({ id, workdir: data.workdir });
|
|
44
51
|
return data;
|
|
45
52
|
}
|
|
@@ -64,7 +71,7 @@ function writeIndex({ id, workdir }) {
|
|
|
64
71
|
index.byWorkdir[key] = id;
|
|
65
72
|
index.last = id;
|
|
66
73
|
index.updatedAt = new Date().toISOString();
|
|
67
|
-
|
|
74
|
+
atomicWriteJson(INDEX_FILE, index);
|
|
68
75
|
}
|
|
69
76
|
catch { }
|
|
70
77
|
}
|
package/dist/transcript.js
CHANGED
|
@@ -20,12 +20,12 @@ export class Transcript {
|
|
|
20
20
|
// Write errors (disk full, file deleted, etc.) arrive as an 'error'
|
|
21
21
|
// event; without a listener this is an uncaught exception.
|
|
22
22
|
this.stream.on('error', (e) => {
|
|
23
|
-
console.error(`transcript:
|
|
23
|
+
console.error(`transcript: write error: ${e.message}`);
|
|
24
24
|
this.enabled = false;
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
27
|
catch (e) {
|
|
28
|
-
console.error(`transcript:
|
|
28
|
+
console.error(`transcript: failed to create file: ${e.message}`);
|
|
29
29
|
this.enabled = false;
|
|
30
30
|
}
|
|
31
31
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zames_pro",
|
|
3
|
-
"version": "2.49.
|
|
3
|
+
"version": "2.49.5",
|
|
4
4
|
"description": "Terminal coding agent over chat.deepseek.com via Playwright",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
],
|
|
39
39
|
"license": "MIT",
|
|
40
40
|
"engines": {
|
|
41
|
-
"node": ">=
|
|
41
|
+
"node": ">=20"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@modelcontextprotocol/sdk": "^1.30.1",
|