@muggleai/works 5.1.0 → 5.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/dist/{chunk-MOHR7QUN.js → chunk-3HSV6EXR.js} +48 -18
- package/dist/{chunk-2BHC6TQR.js → chunk-IIQZLG34.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/index.js +2 -2
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/.cursor-plugin/plugin.json +1 -1
- package/dist/plugin/skills/muggle-preferences/preference-gates/README.md +8 -5
- package/dist/release-manifest.json +4 -4
- package/dist/{src-SS2AL3O7.js → src-KHZUV253.js} +1 -1
- package/package.json +8 -7
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.cursor-plugin/plugin.json +1 -1
- package/plugin/skills/muggle-preferences/preference-gates/README.md +8 -5
|
@@ -6236,6 +6236,11 @@ var PreferenceKey = /* @__PURE__ */ ((PreferenceKey2) => {
|
|
|
6236
6236
|
PreferenceKey2["AutoRebase"] = "autoRebase";
|
|
6237
6237
|
PreferenceKey2["AutoCleanup"] = "autoCleanup";
|
|
6238
6238
|
PreferenceKey2["AutoE2ETest"] = "autoE2ETest";
|
|
6239
|
+
PreferenceKey2["AutoResolveConflicts"] = "autoResolveConflicts";
|
|
6240
|
+
PreferenceKey2["AutoReuseValidationContext"] = "autoReuseValidationContext";
|
|
6241
|
+
PreferenceKey2["AutoRouteBuildToMuggleDo"] = "autoRouteBuildToMuggleDo";
|
|
6242
|
+
PreferenceKey2["AutoWatchPR"] = "autoWatchPR";
|
|
6243
|
+
PreferenceKey2["ReusePreparePlan"] = "reusePreparePlan";
|
|
6239
6244
|
return PreferenceKey2;
|
|
6240
6245
|
})(PreferenceKey || {});
|
|
6241
6246
|
var PreferenceValue = /* @__PURE__ */ ((PreferenceValue2) => {
|
|
@@ -6252,23 +6257,28 @@ var PREFERENCES_FILE_NAME = "preferences.json";
|
|
|
6252
6257
|
var PREFERENCES_PROJECT_DIR_NAME = ".muggle-ai";
|
|
6253
6258
|
var PREFERENCES_VERSION = 1;
|
|
6254
6259
|
var DEFAULT_PREFERENCES = {
|
|
6255
|
-
["autoLogin" /* AutoLogin */]: "
|
|
6256
|
-
["autoSelectProject" /* AutoSelectProject */]: "
|
|
6257
|
-
["autoSelectLocalHost" /* AutoSelectLocalHost */]: "
|
|
6258
|
-
["showElectronBrowser" /* ShowElectronBrowser */]: "
|
|
6259
|
-
["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: "
|
|
6260
|
-
["defaultExecutionMode" /* DefaultExecutionMode */]: "
|
|
6261
|
-
["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: "
|
|
6262
|
-
["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: "
|
|
6263
|
-
["autoDetectChanges" /* AutoDetectChanges */]: "
|
|
6264
|
-
["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: "
|
|
6265
|
-
["autoCreatePR" /* AutoCreatePR */]: "
|
|
6266
|
-
["checkForUpdates" /* CheckForUpdates */]: "
|
|
6267
|
-
["verboseOutput" /* VerboseOutput */]: "
|
|
6268
|
-
["autoUseWorktree" /* AutoUseWorktree */]: "
|
|
6269
|
-
["autoRebase" /* AutoRebase */]: "
|
|
6270
|
-
["autoCleanup" /* AutoCleanup */]: "
|
|
6271
|
-
["autoE2ETest" /* AutoE2ETest */]: "always" /* Always
|
|
6260
|
+
["autoLogin" /* AutoLogin */]: "always" /* Always */,
|
|
6261
|
+
["autoSelectProject" /* AutoSelectProject */]: "always" /* Always */,
|
|
6262
|
+
["autoSelectLocalHost" /* AutoSelectLocalHost */]: "always" /* Always */,
|
|
6263
|
+
["showElectronBrowser" /* ShowElectronBrowser */]: "always" /* Always */,
|
|
6264
|
+
["openTestResultsAfterRun" /* OpenTestResultsAfterRun */]: "always" /* Always */,
|
|
6265
|
+
["defaultExecutionMode" /* DefaultExecutionMode */]: "local" /* Local */,
|
|
6266
|
+
["suggestRelatedUseCases" /* SuggestRelatedUseCases */]: "always" /* Always */,
|
|
6267
|
+
["suggestRelatedTestCases" /* SuggestRelatedTestCases */]: "always" /* Always */,
|
|
6268
|
+
["autoDetectChanges" /* AutoDetectChanges */]: "always" /* Always */,
|
|
6269
|
+
["postPRVisualWalkthrough" /* PostPRVisualWalkthrough */]: "always" /* Always */,
|
|
6270
|
+
["autoCreatePR" /* AutoCreatePR */]: "always" /* Always */,
|
|
6271
|
+
["checkForUpdates" /* CheckForUpdates */]: "always" /* Always */,
|
|
6272
|
+
["verboseOutput" /* VerboseOutput */]: "never" /* Never */,
|
|
6273
|
+
["autoUseWorktree" /* AutoUseWorktree */]: "always" /* Always */,
|
|
6274
|
+
["autoRebase" /* AutoRebase */]: "always" /* Always */,
|
|
6275
|
+
["autoCleanup" /* AutoCleanup */]: "always" /* Always */,
|
|
6276
|
+
["autoE2ETest" /* AutoE2ETest */]: "always" /* Always */,
|
|
6277
|
+
["autoResolveConflicts" /* AutoResolveConflicts */]: "always" /* Always */,
|
|
6278
|
+
["autoReuseValidationContext" /* AutoReuseValidationContext */]: "always" /* Always */,
|
|
6279
|
+
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: "always" /* Always */,
|
|
6280
|
+
["autoWatchPR" /* AutoWatchPR */]: "always" /* Always */,
|
|
6281
|
+
["reusePreparePlan" /* ReusePreparePlan */]: "always" /* Always */
|
|
6272
6282
|
};
|
|
6273
6283
|
var ALWAYS_ASK_NEVER = [
|
|
6274
6284
|
"always" /* Always */,
|
|
@@ -6301,7 +6311,12 @@ var PREFERENCE_ALLOWED_VALUES = {
|
|
|
6301
6311
|
["autoUseWorktree" /* AutoUseWorktree */]: ALWAYS_ASK_NEVER,
|
|
6302
6312
|
["autoRebase" /* AutoRebase */]: ALWAYS_ASK_NEVER,
|
|
6303
6313
|
["autoCleanup" /* AutoCleanup */]: ALWAYS_ASK_NEVER,
|
|
6304
|
-
["autoE2ETest" /* AutoE2ETest */]: ALWAYS_ASK
|
|
6314
|
+
["autoE2ETest" /* AutoE2ETest */]: ALWAYS_ASK,
|
|
6315
|
+
["autoResolveConflicts" /* AutoResolveConflicts */]: ALWAYS_ASK_NEVER,
|
|
6316
|
+
["autoReuseValidationContext" /* AutoReuseValidationContext */]: ALWAYS_ASK_NEVER,
|
|
6317
|
+
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: ALWAYS_ASK_NEVER,
|
|
6318
|
+
["autoWatchPR" /* AutoWatchPR */]: ALWAYS_ASK_NEVER,
|
|
6319
|
+
["reusePreparePlan" /* ReusePreparePlan */]: ALWAYS_ASK_NEVER
|
|
6305
6320
|
};
|
|
6306
6321
|
var PREFERENCES_SCHEMA = {
|
|
6307
6322
|
["autoLogin" /* AutoLogin */]: {
|
|
@@ -6354,6 +6369,21 @@ var PREFERENCES_SCHEMA = {
|
|
|
6354
6369
|
},
|
|
6355
6370
|
["autoE2ETest" /* AutoE2ETest */]: {
|
|
6356
6371
|
description: "Run Stage 6 (E2E acceptance) at the end of every /muggle-do cycle (default always \u2014 running E2E is the point of muggle-do; never is not an option)"
|
|
6372
|
+
},
|
|
6373
|
+
["autoResolveConflicts" /* AutoResolveConflicts */]: {
|
|
6374
|
+
description: "When a rebase onto the default branch hits conflicts, resolve them autonomously behind a verify-or-rollback gate instead of aborting and escalating"
|
|
6375
|
+
},
|
|
6376
|
+
["autoReuseValidationContext" /* AutoReuseValidationContext */]: {
|
|
6377
|
+
description: "When a prior session left an E2E validation context for this working tree, reuse it instead of re-asking the validation questions"
|
|
6378
|
+
},
|
|
6379
|
+
["autoRouteBuildToMuggleDo" /* AutoRouteBuildToMuggleDo */]: {
|
|
6380
|
+
description: "When a prompt looks like a build/implement/fix request, route it through the /muggle-do pipeline (requirements \u2192 build \u2192 impact \u2192 tests \u2192 E2E \u2192 PR \u2192 watcher)"
|
|
6381
|
+
},
|
|
6382
|
+
["autoWatchPR" /* AutoWatchPR */]: {
|
|
6383
|
+
description: "After a test run opens a PR, start a muggle-pr-followup watcher that polls for new reviews and hands them to /muggle-do"
|
|
6384
|
+
},
|
|
6385
|
+
["reusePreparePlan" /* ReusePreparePlan */]: {
|
|
6386
|
+
description: "Reuse the saved prepare plan for this stack (skip discovery, jump to check-running + smoke-test) instead of rediscovering from scratch"
|
|
6357
6387
|
}
|
|
6358
6388
|
};
|
|
6359
6389
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, isFirstRun, writePreferences, DEFAULT_PREFERENCES, getDataDir, PREFERENCES_FILE_NAME, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, getDisclosureCopy, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-
|
|
1
|
+
import { __export, getLogger, getConfig, createChildLogger, buildElectronAppReleaseAssetUrl, getAuthService, hasApiKey, getElectronAppVersion, getElectronAppDir, getPlatformKey, isFirstRun, writePreferences, DEFAULT_PREFERENCES, getDataDir, PREFERENCES_FILE_NAME, isElectronAppInstalled, getElectronAppChecksums, getChecksumForPlatform, verifyFileChecksum, calculateFileChecksum, initTelemetry, Surface, ServiceName, track, EventName, getQaTools, getLocalQaTools, performLogout, performLogin, toolRequiresAuth, getCallerCredentials, hasShownDisclosure, getDisclosureCopy, markDisclosureShown, getBundledElectronAppVersion, getElectronAppVersionSource, getCredentialsFilePath, buildElectronAppChecksumsUrl, __require } from './chunk-3HSV6EXR.js';
|
|
2
2
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
3
|
import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
4
4
|
import { v4 } from 'uuid';
|
|
@@ -736,7 +736,7 @@ async function resolveGsScreenshotUrls(report, opts) {
|
|
|
736
736
|
if (gsUrls.length === 0) {
|
|
737
737
|
return report;
|
|
738
738
|
}
|
|
739
|
-
const mcps = await import('./src-
|
|
739
|
+
const mcps = await import('./src-KHZUV253.js');
|
|
740
740
|
const credentials = await mcps.getCallerCredentialsAsync();
|
|
741
741
|
if (!credentials.bearerToken && !credentials.apiKey) {
|
|
742
742
|
stderrWrite(
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-
|
|
2
|
-
export { createChildLogger, e2e_exports as e2e, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports as localQa, mcp_exports as mcp, e2e_exports as qa, src_exports as shared } from './chunk-
|
|
1
|
+
export { src_exports as commands, createUnifiedMcpServer, server_exports as server } from './chunk-IIQZLG34.js';
|
|
2
|
+
export { createChildLogger, e2e_exports as e2e, getConfig, getLocalQaTools, getLogger, getQaTools, local_exports as localQa, mcp_exports as mcp, e2e_exports as qa, src_exports as shared } from './chunk-3HSV6EXR.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.2.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
7
7
|
"email": "support@muggle-ai.com"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"displayName": "Muggle AI",
|
|
4
4
|
"description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
5
|
-
"version": "5.
|
|
5
|
+
"version": "5.2.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
|
@@ -16,16 +16,19 @@ which uses `local` / `remote` / `ask`).
|
|
|
16
16
|
|
|
17
17
|
## Gate behavior
|
|
18
18
|
|
|
19
|
-
- `always` → take the pro-action, then print silent footer.
|
|
20
|
-
- `never` → take the skip-action, then print silent footer.
|
|
19
|
+
- `always` → take the pro-action, then **always** print the silent footer.
|
|
20
|
+
- `never` → take the skip-action, then **always** print the silent footer.
|
|
21
21
|
- `ask` (or absent) → run Picker 1 (per-key file) → Picker 2 (below).
|
|
22
22
|
|
|
23
23
|
`defaultExecutionMode` uses `local`/`remote` instead of `always`/`never`.
|
|
24
24
|
|
|
25
|
-
## Silent footer (whenever
|
|
25
|
+
## Silent footer (mandatory whenever a prompt is skipped)
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
**
|
|
27
|
+
Whenever a gate resolves to a non-`ask` value and skips its picker, the footer
|
|
28
|
+
below is **required** — every gate, every time, no exceptions. It tells the
|
|
29
|
+
user **what happened**, **why it was silent**, and **how to change it**. The
|
|
30
|
+
`preference-gates-lint` test enforces that this contract exists; omitting the
|
|
31
|
+
footer when a gate fires is a bug. Two lines:
|
|
29
32
|
|
|
30
33
|
```
|
|
31
34
|
✓ <silent action from per-key file>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"release": "5.
|
|
3
|
-
"buildId": "run-
|
|
4
|
-
"commitSha": "
|
|
5
|
-
"buildTime": "2026-06-
|
|
2
|
+
"release": "5.2.0",
|
|
3
|
+
"buildId": "run-54-1",
|
|
4
|
+
"commitSha": "a4e741772fc903d3062be924d0f2eb14881c9eaf",
|
|
5
|
+
"buildTime": "2026-06-12T23:50:15Z",
|
|
6
6
|
"serviceName": "muggle-ai-works-mcp"
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences } from './chunk-
|
|
1
|
+
export { DEFAULT_PREFERENCES, PREFERENCES_FILE_NAME, PREFERENCES_PROJECT_DIR_NAME, PREFERENCES_SCHEMA, PREFERENCES_VERSION, PREFERENCE_ALLOWED_VALUES, PreferenceKey, PreferenceValue, buildElectronAppChecksumsUrl, buildElectronAppReleaseAssetUrl, buildElectronAppReleaseTag, calculateFileChecksum, createApiKeyWithToken, createChildLogger, deleteApiKeyData, deleteCredentials, e2e_exports as e2e, formatPreferencesOneLiner, getApiKey, getApiKeyFilePath, getAuthService, getBundledElectronAppVersion, getCallerCredentials, getCallerCredentialsAsync, getChecksumForPlatform, getConfig, getCredentialsFilePath, getDataDir, getDownloadBaseUrl, getElectronAppChecksums, getElectronAppDir, getElectronAppVersion, getElectronAppVersionSource, getLocalQaTools, getLogger, getPlatformKey, getQaTools, getValidApiKeyData, getValidCredentials, hasApiKey, isElectronAppInstalled, isFirstRun, loadApiKeyData, loadCredentials, local_exports as localQa, mcp_exports as mcp, openBrowserUrl, performLogin, performLogout, pollDeviceCode, e2e_exports as qa, readGlobalPreferences, readProjectPreferences, resetConfig, resetLogger, resetPreference, resolveElectronAppPathOrNull, resolvePreferences, saveApiKey, saveApiKeyData, saveCredentials, startDeviceCodeFlow, toolRequiresAuth, validatePreference, verifyFileChecksum, writePreferences } from './chunk-3HSV6EXR.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@muggleai/works",
|
|
3
3
|
"mcpName": "io.github.multiplex-ai/muggle",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.2.0",
|
|
5
5
|
"description": "Ship quality products with AI-powered E2E acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -38,17 +38,18 @@
|
|
|
38
38
|
"lint:check": "eslint .",
|
|
39
39
|
"typecheck": "tsc --noEmit",
|
|
40
40
|
"test": "vitest run",
|
|
41
|
-
"test:watch": "vitest"
|
|
41
|
+
"test:watch": "vitest",
|
|
42
|
+
"test:gates:behavioral": "tsx internal/skill-gate-eval/src/run.ts"
|
|
42
43
|
},
|
|
43
44
|
"muggleConfig": {
|
|
44
|
-
"electronAppVersion": "1.4.
|
|
45
|
+
"electronAppVersion": "1.4.3",
|
|
45
46
|
"downloadBaseUrl": "https://github.com/multiplex-ai/muggle-ai-works/releases/download",
|
|
46
47
|
"runtimeTargetDefault": "production",
|
|
47
48
|
"checksums": {
|
|
48
|
-
"darwin-arm64": "
|
|
49
|
-
"darwin-x64": "
|
|
50
|
-
"linux-x64": "
|
|
51
|
-
"win32-x64": "
|
|
49
|
+
"darwin-arm64": "c89902e5003614cdb3a00aa12a3774d07f63d3a6450282ea86530bc46969eb55",
|
|
50
|
+
"darwin-x64": "093742c15e7439cf62ddb22a42c7d5cc8c482140c9a981cd06c4f58eb7a48cd4",
|
|
51
|
+
"linux-x64": "adb4d707ce122c3826260a26176ba2ee10bf14f376eed3455a1b0e2202ac4f3f",
|
|
52
|
+
"win32-x64": "d1abae146be3378884c74fc2c2f9d7a272e86695b5ae04fdbea200586ea3bfd2"
|
|
52
53
|
}
|
|
53
54
|
},
|
|
54
55
|
"dependencies": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"description": "Run real-browser end-to-end (E2E) acceptance tests on your web app from any AI coding agent. Generate test scripts from plain English, replay them on localhost, capture screenshots, and validate user flows like signup, checkout, and dashboards. Works across Claude Code, Cursor, Codex, and Windsurf.",
|
|
4
|
-
"version": "5.
|
|
4
|
+
"version": "5.2.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Muggle AI",
|
|
7
7
|
"email": "support@muggle-ai.com"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "muggle",
|
|
3
3
|
"displayName": "Muggle AI",
|
|
4
4
|
"description": "Ship quality products with AI-powered end-to-end (E2E) acceptance testing that validates your web app like a real user — from Claude Code and Cursor to PR.",
|
|
5
|
-
"version": "5.
|
|
5
|
+
"version": "5.2.0",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Muggle AI",
|
|
8
8
|
"email": "support@muggle-ai.com"
|
|
@@ -16,16 +16,19 @@ which uses `local` / `remote` / `ask`).
|
|
|
16
16
|
|
|
17
17
|
## Gate behavior
|
|
18
18
|
|
|
19
|
-
- `always` → take the pro-action, then print silent footer.
|
|
20
|
-
- `never` → take the skip-action, then print silent footer.
|
|
19
|
+
- `always` → take the pro-action, then **always** print the silent footer.
|
|
20
|
+
- `never` → take the skip-action, then **always** print the silent footer.
|
|
21
21
|
- `ask` (or absent) → run Picker 1 (per-key file) → Picker 2 (below).
|
|
22
22
|
|
|
23
23
|
`defaultExecutionMode` uses `local`/`remote` instead of `always`/`never`.
|
|
24
24
|
|
|
25
|
-
## Silent footer (whenever
|
|
25
|
+
## Silent footer (mandatory whenever a prompt is skipped)
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
**
|
|
27
|
+
Whenever a gate resolves to a non-`ask` value and skips its picker, the footer
|
|
28
|
+
below is **required** — every gate, every time, no exceptions. It tells the
|
|
29
|
+
user **what happened**, **why it was silent**, and **how to change it**. The
|
|
30
|
+
`preference-gates-lint` test enforces that this contract exists; omitting the
|
|
31
|
+
footer when a gate fires is a bug. Two lines:
|
|
29
32
|
|
|
30
33
|
```
|
|
31
34
|
✓ <silent action from per-key file>
|