editmamei 1.4.0 → 1.5.1

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.
@@ -83,6 +83,11 @@ const openDocumentSchema = {
83
83
  description: 'Suppress all PS dialogs during open (raw/HEIC use last-used ACR settings). Default true for pipeline use.',
84
84
  default: true,
85
85
  },
86
+ bit_depth: {
87
+ type: 'number',
88
+ enum: [8, 16],
89
+ description: 'Open-time bits per channel, RAW sources only. Set this here rather than converting later: ps_convert_image_mode FLATTENS the document, so depth cannot be changed once an edit stack exists. Prefer 16 for anything with heavy gradients (skies, skin, long tonal moves). Ignored for non-raw files, and the returned bits_per_channel always reports what was actually opened.',
90
+ },
86
91
  },
87
92
  required: ['file_path'],
88
93
  };
@@ -294,6 +299,10 @@ export function createDocumentTools(connection, snippetClient) {
294
299
  },
295
300
  already_open: { type: 'boolean' },
296
301
  file_path: { type: 'string' },
302
+ bit_depth_warning: {
303
+ type: 'string',
304
+ description: 'Present only when a requested bit_depth was not what the document actually opened at — because the file is not a raw source, or Photoshop declined the requested depth. Absent means bits_per_channel is what you asked for.',
305
+ },
297
306
  context: { type: 'object' },
298
307
  },
299
308
  required: ['success'],
@@ -524,8 +533,21 @@ async function openDocumentPipeline(connection, snippetClient, rawArgs) {
524
533
  const args = validateArgs(openDocumentSchema, rawArgs);
525
534
  filePath = args.file_path;
526
535
  const suppressDialogs = args.suppress_dialogs;
527
- const script = await snippetClient.build('openDocumentPipeline', { filePath, suppressDialogs });
536
+ const bitDepth = args.bit_depth;
537
+ const script = await snippetClient.build('openDocumentPipeline', {
538
+ filePath,
539
+ suppressDialogs,
540
+ rawBits: bitDepth ?? 0,
541
+ });
528
542
  const result = await runScript(connection, script, OPEN_DOCUMENT_TIMEOUT_MS);
543
+ const payload = result;
544
+ if (bitDepth !== undefined && typeof payload.bits_per_channel === 'number') {
545
+ if (payload.bits_per_channel !== bitDepth) {
546
+ payload.bit_depth_warning = payload.is_raw_source
547
+ ? `Requested ${bitDepth}-bit but Photoshop opened ${payload.bits_per_channel}-bit.`
548
+ : `bit_depth applies to RAW sources only; this file opened at ${payload.bits_per_channel}-bit.`;
549
+ }
550
+ }
529
551
  return {
530
552
  content: [
531
553
  {
@@ -101,7 +101,15 @@ export function updateMessage(channel, latest) {
101
101
  return `Download editmamei.mcpb (v${latest}) from ${RELEASES_URL} and reinstall the Claude Desktop extension.`;
102
102
  case 'dev':
103
103
  return `You're on a local dev build — pull the latest source and rebuild.`;
104
- case 'npm':
104
+ case 'npx':
105
+ return `The next \`npx -y editmamei\` picks up v${latest} automatically — just restart your AI client.`;
106
+ case 'source':
107
+ return `You're running Editmamei from a source checkout — pull the latest changes and rebuild.`;
108
+ case 'npm_local':
109
+ return `Editmamei is installed locally in a project — update the \`editmamei\` dependency in that project (e.g. \`npm install editmamei@latest\`) and restart your MCP client.`;
110
+ case 'unknown':
111
+ return `Editmamei v${latest} is available. Update it the way you installed it, then restart your MCP client.`;
112
+ case 'npm_global':
105
113
  default:
106
114
  return `Run: npm install -g editmamei@latest (then restart your MCP client).`;
107
115
  }
@@ -110,7 +118,7 @@ export function shouldCheckForUpdate(updateCheckEnabled, env = process.env) {
110
118
  const inTest = env.VITEST !== undefined || env.NODE_ENV === 'test';
111
119
  return updateCheckEnabled === true && !inTest;
112
120
  }
113
- export async function checkForUpdate(opts = {}) {
121
+ export async function checkForUpdateWithStatus(opts = {}) {
114
122
  try {
115
123
  const env = opts.env ?? process.env;
116
124
  const current = opts.current ?? VERSION;
@@ -118,19 +126,25 @@ export async function checkForUpdate(opts = {}) {
118
126
  const fetchLatest = opts.fetchLatest ?? httpFetchLatest();
119
127
  const manifest = await fetchLatest(resolveUpdateCheckUrl(env), opts.timeoutMs ?? 4000);
120
128
  if (!manifest || !parseSemver(manifest.version))
121
- return null;
129
+ return { status: 'failed', info: null };
122
130
  const latest = manifest.version;
123
131
  if (!isNewer(latest, current))
124
- return null;
132
+ return { status: 'current', info: null };
125
133
  return {
126
- current,
127
- latest,
128
- channel,
129
- how_to_update: updateMessage(channel, latest),
130
- fixed_tools: fixedToolsSince(manifest.fixesByVersion, current, latest),
134
+ status: 'newer',
135
+ info: {
136
+ current,
137
+ latest,
138
+ channel,
139
+ how_to_update: updateMessage(channel, latest),
140
+ fixed_tools: fixedToolsSince(manifest.fixesByVersion, current, latest),
141
+ },
131
142
  };
132
143
  }
133
144
  catch {
134
- return null;
145
+ return { status: 'failed', info: null };
135
146
  }
136
147
  }
148
+ export async function checkForUpdate(opts = {}) {
149
+ return (await checkForUpdateWithStatus(opts)).info;
150
+ }
@@ -267,7 +267,7 @@ export class SessionLog {
267
267
  this.metaEmitted = true;
268
268
  await this.writeLine(JSON.stringify(this.buildMetaEntry()));
269
269
  }
270
- async append(entry, result) {
270
+ async append(entry, result, resultBytes) {
271
271
  if (!this.metaEmitted) {
272
272
  await this.emitMeta();
273
273
  }
@@ -277,7 +277,7 @@ export class SessionLog {
277
277
  const callKey = JSON.stringify({ tool: entry.tool, args: sanitizedArgs });
278
278
  const retrySignal = callKey === this.lastCallKey;
279
279
  this.lastCallKey = callKey;
280
- const resultBytes = computeResultBytes(result);
280
+ const finalResultBytes = resultBytes !== undefined ? resultBytes : computeResultBytes(result);
281
281
  let hoisted = {};
282
282
  try {
283
283
  hoisted = hoistContextScalars(result);
@@ -302,7 +302,7 @@ export class SessionLog {
302
302
  edition: EDITION,
303
303
  platform: process.platform,
304
304
  ps_version: this.psVersion,
305
- result_bytes: resultBytes,
305
+ result_bytes: finalResultBytes,
306
306
  ...hoisted,
307
307
  ...(errorClass !== null ? { error_class: errorClass } : {}),
308
308
  retry_signal: retrySignal,