@daemux/store-automator 0.10.67 → 0.10.68

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.
@@ -5,14 +5,14 @@
5
5
  },
6
6
  "metadata": {
7
7
  "description": "App Store & Google Play automation for Flutter apps",
8
- "version": "0.10.67"
8
+ "version": "0.10.68"
9
9
  },
10
10
  "plugins": [
11
11
  {
12
12
  "name": "store-automator",
13
13
  "source": "./plugins/store-automator",
14
14
  "description": "3 agents for app store publishing: reviewer, meta-creator, media-designer",
15
- "version": "0.10.67",
15
+ "version": "0.10.68",
16
16
  "keywords": [
17
17
  "flutter",
18
18
  "app-store",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daemux/store-automator",
3
- "version": "0.10.67",
3
+ "version": "0.10.68",
4
4
  "description": "Full App Store & Google Play automation for Flutter apps with Claude Code agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "store-automator",
3
- "version": "0.10.67",
3
+ "version": "0.10.68",
4
4
  "description": "App Store & Google Play automation agents for Flutter app publishing",
5
5
  "author": {
6
6
  "name": "Daemux"
package/src/templates.mjs CHANGED
@@ -3,9 +3,11 @@ import { join } from 'node:path';
3
3
  import { ensureDir } from './utils.mjs';
4
4
  import { backupIfChanging } from './backup.mjs';
5
5
 
6
+ const PLUGIN_NAME = 'daemux-store-automator';
6
7
  const SENTINEL_BEGIN = '<!-- BEGIN daemux-store-automator -->';
7
8
  const SENTINEL_END = '<!-- END daemux-store-automator -->';
8
9
  const SENTINEL_BLOCK_RE = /<!-- BEGIN daemux-store-automator -->[\s\S]*?<!-- END daemux-store-automator -->/;
10
+ const FOREIGN_SENTINEL_RE = /<!-- BEGIN daemux-[a-z0-9-]+ -->[\s\S]*?<!-- END daemux-[a-z0-9-]+ -->/g;
9
11
 
10
12
  const FILE_COPIES = [
11
13
  ['ci.config.yaml.template', 'ci.config.yaml'],
@@ -63,6 +65,12 @@ function looksLikeUnsentineledPluginContent(existing) {
63
65
  return startsWithHeader && hasFastlane;
64
66
  }
65
67
 
68
+ function hasForeignSentinels(existing) {
69
+ const matches = existing.match(FOREIGN_SENTINEL_RE);
70
+ if (!matches) return false;
71
+ return matches.some((m) => !m.includes(PLUGIN_NAME));
72
+ }
73
+
66
74
  function composeNewFileContent(existing, wrappedBlock) {
67
75
  if (!existing) {
68
76
  return wrappedBlock;
@@ -71,6 +79,13 @@ function composeNewFileContent(existing, wrappedBlock) {
71
79
  return existing.replace(SENTINEL_BLOCK_RE, wrappedBlock.replace(/\n$/, ''));
72
80
  }
73
81
  if (looksLikeUnsentineledPluginContent(existing)) {
82
+ if (hasForeignSentinels(existing)) {
83
+ console.log(
84
+ 'Note: another Daemux plugin sentinel block detected. Appending updated ' +
85
+ 'plugin block; you may want to manually remove the older unsentineled content.'
86
+ );
87
+ return `${existing.trimEnd()}\n\n${wrappedBlock}`;
88
+ }
74
89
  return wrappedBlock;
75
90
  }
76
91
  const sep = existing.endsWith('\n') ? '' : '\n';
package/src/uninstall.mjs CHANGED
@@ -12,10 +12,7 @@ import {
12
12
  } from './utils.mjs';
13
13
  import { removeMcpServers } from './mcp-setup.mjs';
14
14
  import { backupIfChanging, pruneBackups } from './backup.mjs';
15
- import {
16
- readManagedSettings, getLedgerPath,
17
- HISTORICAL_ENV_KEYS, HISTORICAL_ENV_VALUES,
18
- } from './managed-settings.mjs';
15
+ import { readManagedSettings, getLedgerPath } from './managed-settings.mjs';
19
16
 
20
17
  const SENTINEL_BEGIN = '<!-- BEGIN daemux-store-automator -->';
21
18
  const SENTINEL_END = '<!-- END daemux-store-automator -->';
@@ -127,76 +124,36 @@ function cleanClaudeMd(baseDir, scopeLabel) {
127
124
  }
128
125
  }
129
126
 
130
- function looksLikeHistoricalPluginStatusLine(current) {
131
- return Boolean(
132
- current
133
- && typeof current === 'object'
134
- && current.type === 'command'
135
- && typeof current.command === 'string'
136
- && current.command.includes('context_window')
137
- );
138
- }
139
-
140
- function pruneManagedEnv(settings, envKeys, envValues) {
141
- if (!settings.env) return false;
142
- let modified = false;
143
- for (const key of envKeys) {
144
- if (!(key in settings.env)) continue;
145
- const expected = envValues ? envValues[key] : undefined;
146
- if (expected === undefined || settings.env[key] === expected) {
147
- delete settings.env[key];
148
- modified = true;
149
- } else {
150
- console.log(`Preserving user-modified env.${key} in settings.json`);
151
- }
152
- }
153
- if (Object.keys(settings.env).length === 0) delete settings.env;
154
- return modified;
155
- }
156
-
157
- function pruneManagedStatusLine(settings, ledgerStatusLine) {
158
- if (!settings.statusLine) return false;
159
-
160
- if (ledgerStatusLine) {
161
- if (ledgerStatusLine.wasSet !== true) return false;
162
- const managed = ledgerStatusLine.content;
163
- if (JSON.stringify(settings.statusLine) !== JSON.stringify(managed)) {
164
- console.log('Preserving user-modified statusLine in settings.json');
165
- return false;
166
- }
167
- delete settings.statusLine;
168
- return true;
169
- }
170
-
171
- if (!looksLikeHistoricalPluginStatusLine(settings.statusLine)) {
172
- console.log('Preserving non-plugin statusLine in settings.json (no ledger, signature mismatch)');
173
- return false;
174
- }
175
- delete settings.statusLine;
176
- return true;
177
- }
178
-
179
127
  function cleanSettings(baseDir, scopeLabel, ledger) {
180
128
  const settingsPath = join(baseDir, 'settings.json');
181
129
  if (!existsSync(settingsPath)) return;
182
130
 
183
- let settings;
184
131
  try {
185
- settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
132
+ JSON.parse(readFileSync(settingsPath, 'utf8'));
186
133
  } catch {
187
134
  return;
188
135
  }
189
136
 
190
- const envKeys = ledger?.envKeys ?? HISTORICAL_ENV_KEYS;
191
- const envValues = ledger?.envValues ?? HISTORICAL_ENV_VALUES;
192
- const envChanged = pruneManagedEnv(settings, envKeys, envValues);
193
- const statusLineChanged = pruneManagedStatusLine(settings, ledger?.statusLine);
137
+ // Env keys are intentionally NOT removed on uninstall. CLAUDE_CODE_ENABLE_TASKS
138
+ // and CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS are Claude-Code-level feature flags
139
+ // shared with other Daemux plugins (e.g. default-development). Uninstalling
140
+ // one plugin must not silently break another.
141
+ const ledgerEnvKeys = ledger?.envKeys ?? [];
142
+ if (ledgerEnvKeys.length > 0) {
143
+ console.log(
144
+ `Note: env keys left in settings.json (may be shared with other plugins): ${ledgerEnvKeys.join(', ')}`
145
+ );
146
+ }
194
147
 
195
- if (!envChanged && !statusLineChanged) return;
148
+ // statusLine is intentionally NOT removed on uninstall. Multiple Daemux plugins
149
+ // may inject the same statusLine; deleting it here would remove content that
150
+ // another plugin still relies on (same class of bug as the shared env-key fix).
151
+ if (ledger?.statusLine?.wasSet) {
152
+ console.log(
153
+ 'Note: statusLine left in settings.json (may be shared with other plugins).'
154
+ );
155
+ }
196
156
 
197
- const newRaw = JSON.stringify(settings, null, 2) + '\n';
198
- backupIfChanging(settingsPath, newRaw);
199
- writeFileSync(settingsPath, newRaw, 'utf8');
200
157
  console.log(`Cleaned ${scopeLabel} settings`);
201
158
  }
202
159