pumuki 6.3.69 → 6.3.70
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/README.md +1 -1
- package/docs/operations/RELEASE_NOTES.md +6 -0
- package/docs/product/CONFIGURATION.md +4 -0
- package/docs/product/USAGE.md +4 -1
- package/integrations/evidence/generateEvidence.test.ts +24 -1
- package/integrations/evidence/generateEvidence.ts +18 -1
- package/integrations/evidence/writeEvidence.ts +1 -0
- package/integrations/git/runPlatformGateEvidence.ts +45 -0
- package/package.json +1 -1
- package/scripts/framework-menu-system-notifications-macos-swift-source.ts +6 -1
- package/scripts/framework-menu-system-notifications-macos.ts +28 -4
package/README.md
CHANGED
|
@@ -37,7 +37,7 @@ npx --yes pumuki status
|
|
|
37
37
|
npx --yes pumuki doctor --json
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
Desde **6.3.63**, `npm install` en la raíz de un repo **Git** dispara un `postinstall` que ejecuta **`pumuki install` solo** (hooks `pre-commit` / `pre-push`, lifecycle, evidencia cuando aplica). **Pumuki no depende de ningún IDE** para el baseline: no toca `.cursor/` ni otros ficheros de editor por defecto. Desde **6.3.68**, cada hook gestionado ejecuta **`pumuki-pre-write` antes** de `pumuki-pre-commit` / `pumuki-pre-push` (stage **PRE_WRITE** vía Git). Saltar solo PRE_WRITE en hooks: `PUMUKI_SKIP_CHAINED_PRE_WRITE=1`. Desde **6.3.69**, esos mismos hooks aplican también **git-flow en ramas protegidas** (`GITFLOW_PROTECTED_BRANCH`) e **higiene de worktree** (`PUMUKI_PREWRITE_WORKTREE_*` / códigos `EVIDENCE_PREWRITE_WORKTREE_*`) cuando la evidencia es válida; el **modal macOS** de bloqueo (Desactivar / Silenciar 30 min / Mantener activas) queda **activo por defecto** si las notificaciones están habilitadas (`"blockedDialogEnabled": false` o `PUMUKI_MACOS_BLOCKED_DIALOG=0` para apagarlo). Tras install, si no existía, aparece **`.pumuki/adapter.json`** con los comandos de hooks y **MCP stdio** para referencia o para clientes que los registren manualmente. Para generar también config de IDE: **`pumuki install --with-mcp --agent=cursor`** (u otro) o **`pumuki bootstrap --enterprise --agent=…`**. Desactivar el postinstall: `PUMUKI_SKIP_POSTINSTALL=1`. En CI suele saltarse solo (`CI=true`). En **6.3.64+**, las notificaciones del sistema en plataformas sin banner nativo se reflejan en **stderr** por defecto (`PUMUKI_DISABLE_STDERR_NOTIFICATIONS=1` para silenciarlas). En **6.3.69+**, un `gate.blocked` en macOS también deja una copia en **stderr** por defecto (`PUMUKI_DISABLE_GATE_BLOCKED_STDERR_MIRROR=1` para desactivar solo eso).
|
|
40
|
+
Desde **6.3.63**, `npm install` en la raíz de un repo **Git** dispara un `postinstall` que ejecuta **`pumuki install` solo** (hooks `pre-commit` / `pre-push`, lifecycle, evidencia cuando aplica). **Pumuki no depende de ningún IDE** para el baseline: no toca `.cursor/` ni otros ficheros de editor por defecto. Desde **6.3.68**, cada hook gestionado ejecuta **`pumuki-pre-write` antes** de `pumuki-pre-commit` / `pumuki-pre-push` (stage **PRE_WRITE** vía Git). Saltar solo PRE_WRITE en hooks: `PUMUKI_SKIP_CHAINED_PRE_WRITE=1`. Desde **6.3.69**, esos mismos hooks aplican también **git-flow en ramas protegidas** (`GITFLOW_PROTECTED_BRANCH`) e **higiene de worktree** (`PUMUKI_PREWRITE_WORKTREE_*` / códigos `EVIDENCE_PREWRITE_WORKTREE_*`) cuando la evidencia es válida; el **modal macOS** de bloqueo (Desactivar / Silenciar 30 min / Mantener activas) queda **activo por defecto** si las notificaciones están habilitadas (`"blockedDialogEnabled": false` o `PUMUKI_MACOS_BLOCKED_DIALOG=0` para apagarlo). Tras install, si no existía, aparece **`.pumuki/adapter.json`** con los comandos de hooks y **MCP stdio** para referencia o para clientes que los registren manualmente. Para generar también config de IDE: **`pumuki install --with-mcp --agent=cursor`** (u otro) o **`pumuki bootstrap --enterprise --agent=…`**. Desactivar el postinstall: `PUMUKI_SKIP_POSTINSTALL=1`. En CI suele saltarse solo (`CI=true`). En **6.3.64+**, las notificaciones del sistema en plataformas sin banner nativo se reflejan en **stderr** por defecto (`PUMUKI_DISABLE_STDERR_NOTIFICATIONS=1` para silenciarlas). En **6.3.69+**, un `gate.blocked` en macOS también deja una copia en **stderr** por defecto (`PUMUKI_DISABLE_GATE_BLOCKED_STDERR_MIRROR=1` para desactivar solo eso). Desde **6.3.70**, si **`.ai_evidence.json` está versionado** y **PRE_PUSH** no bloquea, ese archivo **no se reescribe** en el push (compatibilidad con **pre-commit** como hook de **pre-push**); para forzar escritura: `PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE=1`. Con modal de bloqueo activo, el panel interactivo prioriza foco/clics y se evita el banner duplicado.
|
|
41
41
|
|
|
42
42
|
Fallback (equivalent in pasos separados):
|
|
43
43
|
|
|
@@ -6,6 +6,12 @@ This file keeps only the operational highlights and rollout notes that matter wh
|
|
|
6
6
|
|
|
7
7
|
## 2026-04 (CLI stability and macOS notifications)
|
|
8
8
|
|
|
9
|
+
### 2026-04-06 (v6.3.70)
|
|
10
|
+
|
|
11
|
+
- **Consumidores con pre-commit en pre-push**: con `.ai_evidence.json` **versionado**, `PRE_PUSH` en **ALLOW/WARN** omite persistir en disco para no ensuciar el árbol tras el gate; variable `PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE=1` si necesitas el snapshot `PRE_PUSH` en fichero trackeado (puede exigir flujo de commit explícito).
|
|
12
|
+
- **macOS bloqueo**: un solo canal interactivo cuando el modal está activo (sin banner `osascript` paralelo); panel Swift más fiable para foco y clics en botones.
|
|
13
|
+
- **Rollout**: `pumuki@6.3.70`, repin en monorepos (p. ej. RuralGO); `npm test` / `git push` con hooks encadenados como validación.
|
|
14
|
+
|
|
9
15
|
### 2026-04-05 (v6.3.69)
|
|
10
16
|
|
|
11
17
|
- **Hooks = política de repo**: `PRE_COMMIT` / `PRE_PUSH` / `CI` / `PRE_WRITE` incorporan **`GITFLOW_PROTECTED_BRANCH`** y **higiene de worktree** (`EVIDENCE_PREWRITE_WORKTREE_*`, env `PUMUKI_PREWRITE_WORKTREE_*`) vía fusión con `evaluateAiGate` en `runPlatformGate`.
|
|
@@ -317,6 +317,10 @@ Environment variables:
|
|
|
317
317
|
- `PUMUKI_PREWRITE_WORKTREE_WARN_THRESHOLD` (default: `12`)
|
|
318
318
|
- `PUMUKI_PREWRITE_WORKTREE_BLOCK_THRESHOLD` (default: `24`)
|
|
319
319
|
|
|
320
|
+
## Evidencia en PRE_PUSH con `.ai_evidence.json` trackeado
|
|
321
|
+
|
|
322
|
+
- `PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE` (`1|true|yes`): fuerza la escritura del snapshot en `PRE_PUSH` aunque `.ai_evidence.json` esté versionado. Por defecto (sin esta variable), si el fichero está en el índice de git y el outcome no es `BLOCK`, Pumuki **no** muta el archivo para no romper hooks encadenados (p. ej. `pre-commit` ejecutado desde `pre-push`).
|
|
323
|
+
|
|
320
324
|
Codes emitted:
|
|
321
325
|
|
|
322
326
|
- `EVIDENCE_PREWRITE_WORKTREE_WARN` (warning, still `ALLOWED`)
|
package/docs/product/USAGE.md
CHANGED
|
@@ -679,6 +679,7 @@ npm run toolkit:clean-artifacts -- --dry-run
|
|
|
679
679
|
- Fails safe (`exit 1`) with guidance when no upstream is configured.
|
|
680
680
|
- Evaluates `upstream..HEAD` commit range.
|
|
681
681
|
- Requires valid SDD/OpenSpec status (session + active change + validation).
|
|
682
|
+
- Si `.ai_evidence.json` está **versionado** en git y el resultado del gate **no** es `BLOCK` (`PASS`/`WARN`), Pumuki **no reescribe** ese archivo en disco. Así se evita que integraciones tipo `pre-commit` (p. ej. como hook de `pre-push`) fallen con “files were modified by this hook” tras un `decision=ALLOW`. El snapshot en el último commit sigue siendo el generado en `PRE_COMMIT` hasta el siguiente commit. Para forzar la escritura del snapshot `PRE_PUSH` en un fichero trackeado, usa `PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE=1` (puede exigir un flujo de commit/evidencia explícito).
|
|
682
683
|
|
|
683
684
|
### CI
|
|
684
685
|
|
|
@@ -706,10 +707,12 @@ Resolver source: `integrations/git/resolveGitRefs.ts`.
|
|
|
706
707
|
|
|
707
708
|
## Evidence output
|
|
708
709
|
|
|
709
|
-
|
|
710
|
+
Cada ejecución del gate escribe evidencia determinista en:
|
|
710
711
|
|
|
711
712
|
- `.ai_evidence.json`
|
|
712
713
|
|
|
714
|
+
Excepción: en `PRE_PUSH`, si el fichero está trackeado y el outcome no es `BLOCK`, la escritura al path anterior se omite (ver sección PRE_PUSH arriba). La telemetría interna del gate sigue generándose; solo se evita mutar el árbol de trabajo.
|
|
715
|
+
|
|
713
716
|
Schema and behavior:
|
|
714
717
|
|
|
715
718
|
- `version: "2.1"` is the source of truth
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { execFileSync } from 'node:child_process';
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import test from 'node:test';
|
|
6
6
|
import { withTempDir } from '../__tests__/helpers/tempDir';
|
|
@@ -61,6 +61,29 @@ test('generateEvidence compone build + write y persiste .ai_evidence.json', asyn
|
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
+
test('generateEvidence omite escritura a disco cuando skipDiskWrite y repoRoot son válidos', async () => {
|
|
65
|
+
await withTempDir('pumuki-generate-evidence-skip-', async (tempRoot) => {
|
|
66
|
+
initGitRepo(tempRoot);
|
|
67
|
+
const evidencePath = join(tempRoot, '.ai_evidence.json');
|
|
68
|
+
writeFileSync(evidencePath, '{"version":"2.1","pinned":true}\n', 'utf8');
|
|
69
|
+
|
|
70
|
+
const result = generateEvidence({
|
|
71
|
+
stage: 'PRE_PUSH',
|
|
72
|
+
gateOutcome: 'PASS',
|
|
73
|
+
findings: [],
|
|
74
|
+
detectedPlatforms: {},
|
|
75
|
+
loadedRulesets: [],
|
|
76
|
+
repoRoot: tempRoot,
|
|
77
|
+
skipDiskWrite: true,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
assert.equal(result.evidence.snapshot.stage, 'PRE_PUSH');
|
|
81
|
+
assert.equal(result.write.ok, true);
|
|
82
|
+
assert.equal(result.write.skipped, true);
|
|
83
|
+
assert.equal(readFileSync(evidencePath, 'utf8'), '{"version":"2.1","pinned":true}\n');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
64
87
|
test('generateEvidence mantiene evidencia en memoria aunque write falle', async () => {
|
|
65
88
|
await withTempDir('pumuki-generate-evidence-write-error-', async (tempRoot) => {
|
|
66
89
|
initGitRepo(tempRoot);
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
1
2
|
import { buildEvidence, type BuildEvidenceParams } from './buildEvidence';
|
|
2
3
|
import type { AiEvidenceV2_1 } from './schema';
|
|
3
4
|
import { writeEvidence, type WriteEvidenceResult } from './writeEvidence';
|
|
4
5
|
|
|
6
|
+
const EVIDENCE_FILE_BASENAME = '.ai_evidence.json';
|
|
7
|
+
|
|
5
8
|
export type GenerateEvidenceResult = {
|
|
6
9
|
evidence: AiEvidenceV2_1;
|
|
7
10
|
write: WriteEvidenceResult;
|
|
@@ -9,11 +12,25 @@ export type GenerateEvidenceResult = {
|
|
|
9
12
|
|
|
10
13
|
export type GenerateEvidenceParams = BuildEvidenceParams & {
|
|
11
14
|
repoRoot?: string;
|
|
15
|
+
skipDiskWrite?: boolean;
|
|
12
16
|
};
|
|
13
17
|
|
|
14
18
|
export const generateEvidence = (params: GenerateEvidenceParams): GenerateEvidenceResult => {
|
|
15
|
-
const { repoRoot, ...buildParams } = params;
|
|
19
|
+
const { repoRoot, skipDiskWrite, ...buildParams } = params;
|
|
16
20
|
const evidence = buildEvidence(buildParams);
|
|
21
|
+
if (skipDiskWrite === true) {
|
|
22
|
+
if (typeof repoRoot !== 'string' || repoRoot.length === 0) {
|
|
23
|
+
throw new Error('generateEvidence: repoRoot is required when skipDiskWrite is true');
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
evidence,
|
|
27
|
+
write: {
|
|
28
|
+
ok: true,
|
|
29
|
+
path: join(repoRoot, EVIDENCE_FILE_BASENAME),
|
|
30
|
+
skipped: true,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
17
34
|
const write = writeEvidence(evidence, { repoRoot });
|
|
18
35
|
return { evidence, write };
|
|
19
36
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Finding } from '../../core/gate/Finding';
|
|
2
2
|
import type { GateOutcome } from '../../core/gate/GateOutcome';
|
|
3
3
|
import type { GateStage } from '../../core/gate/GateStage';
|
|
4
|
+
import { GitService } from './GitService';
|
|
4
5
|
import { rulePackVersions } from '../../core/rules/presets/rulePackVersions';
|
|
5
6
|
import type { RuleSet } from '../../core/rules/RuleSet';
|
|
6
7
|
import type { SkillsRuleSetLoadResult } from '../config/skillsRuleSet';
|
|
@@ -17,14 +18,51 @@ import { normalizeSnapshotRulesCoverage } from '../evidence/rulesCoverage';
|
|
|
17
18
|
import type { TddBddSnapshot } from '../tdd/types';
|
|
18
19
|
import { emitGateTelemetryEvent } from '../telemetry/gateTelemetry';
|
|
19
20
|
|
|
21
|
+
const TRACKED_EVIDENCE_RELATIVE_PATH = '.ai_evidence.json';
|
|
22
|
+
|
|
23
|
+
const isTruthyEnvFlag = (value?: string): boolean => {
|
|
24
|
+
if (!value) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const normalized = value.trim().toLowerCase();
|
|
28
|
+
return normalized === '1' || normalized === 'true' || normalized === 'yes';
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const defaultIsEvidencePathTracked = (repoRoot: string, relativePath: string): boolean => {
|
|
32
|
+
try {
|
|
33
|
+
new GitService().runGit(['ls-files', '--error-unmatch', '--', relativePath], repoRoot);
|
|
34
|
+
return true;
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const shouldSkipPrePushTrackedEvidenceDiskWrite = (params: {
|
|
41
|
+
stage: GateStage;
|
|
42
|
+
gateOutcome: GateOutcome;
|
|
43
|
+
repoRoot: string;
|
|
44
|
+
isEvidencePathTracked: (repoRoot: string, relativePath: string) => boolean;
|
|
45
|
+
}): boolean => {
|
|
46
|
+
if (isTruthyEnvFlag(process.env.PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return (
|
|
50
|
+
params.stage === 'PRE_PUSH' &&
|
|
51
|
+
params.gateOutcome !== 'BLOCK' &&
|
|
52
|
+
params.isEvidencePathTracked(params.repoRoot, TRACKED_EVIDENCE_RELATIVE_PATH)
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
20
56
|
export type PlatformGateEvidenceDependencies = {
|
|
21
57
|
generateEvidence: typeof generateEvidence;
|
|
22
58
|
emitGateTelemetryEvent: typeof emitGateTelemetryEvent;
|
|
59
|
+
isEvidencePathTracked: (repoRoot: string, relativePath: string) => boolean;
|
|
23
60
|
};
|
|
24
61
|
|
|
25
62
|
const defaultDependencies: PlatformGateEvidenceDependencies = {
|
|
26
63
|
generateEvidence,
|
|
27
64
|
emitGateTelemetryEvent,
|
|
65
|
+
isEvidencePathTracked: defaultIsEvidencePathTracked,
|
|
28
66
|
};
|
|
29
67
|
|
|
30
68
|
export const emitPlatformGateEvidence = (params: {
|
|
@@ -58,6 +96,12 @@ export const emitPlatformGateEvidence = (params: {
|
|
|
58
96
|
const evaluationMetrics = normalizeSnapshotEvaluationMetrics(params.evaluationMetrics);
|
|
59
97
|
const rulesCoverage = normalizeSnapshotRulesCoverage(params.stage, params.rulesCoverage);
|
|
60
98
|
const repoState = captureRepoState(params.repoRoot);
|
|
99
|
+
const skipDiskWrite = shouldSkipPrePushTrackedEvidenceDiskWrite({
|
|
100
|
+
stage: params.stage,
|
|
101
|
+
gateOutcome: params.gateOutcome,
|
|
102
|
+
repoRoot: params.repoRoot,
|
|
103
|
+
isEvidencePathTracked: activeDependencies.isEvidencePathTracked,
|
|
104
|
+
});
|
|
61
105
|
|
|
62
106
|
activeDependencies.generateEvidence({
|
|
63
107
|
stage: params.stage,
|
|
@@ -70,6 +114,7 @@ export const emitPlatformGateEvidence = (params: {
|
|
|
70
114
|
...(params.tddBdd ? { tddBdd: params.tddBdd } : {}),
|
|
71
115
|
...(params.memoryShadow ? { memoryShadow: params.memoryShadow } : {}),
|
|
72
116
|
repoRoot: params.repoRoot,
|
|
117
|
+
...(skipDiskWrite ? { skipDiskWrite: true } : {}),
|
|
73
118
|
previousEvidence: params.evidenceService.loadPreviousEvidence(params.repoRoot),
|
|
74
119
|
detectedPlatforms: params.evidenceService.toDetectedPlatformsRecord(params.detectedPlatforms),
|
|
75
120
|
loadedRulesets: params.evidenceService.buildRulesetState({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.70",
|
|
4
4
|
"description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export const SWIFT_BLOCKED_DIALOG_SOURCE = String.raw`import AppKit
|
|
2
2
|
import Foundation
|
|
3
3
|
|
|
4
|
+
final class KeyableFloatingPanel: NSPanel {
|
|
5
|
+
override var canBecomeKey: Bool { true }
|
|
6
|
+
}
|
|
7
|
+
|
|
4
8
|
struct DialogConfig {
|
|
5
9
|
let title: String
|
|
6
10
|
let cause: String
|
|
@@ -108,12 +112,13 @@ final class DialogController: NSObject, NSApplicationDelegate, NSWindowDelegate
|
|
|
108
112
|
y: screenFrame.minY + margin
|
|
109
113
|
)
|
|
110
114
|
|
|
111
|
-
let panel =
|
|
115
|
+
let panel = KeyableFloatingPanel(
|
|
112
116
|
contentRect: NSRect(x: origin.x, y: origin.y, width: width, height: height),
|
|
113
117
|
styleMask: [.titled, .closable, .fullSizeContentView],
|
|
114
118
|
backing: .buffered,
|
|
115
119
|
defer: false
|
|
116
120
|
)
|
|
121
|
+
panel.becomesKeyOnlyIfNeeded = false
|
|
117
122
|
panel.level = .floating
|
|
118
123
|
panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
|
|
119
124
|
panel.titleVisibility = .hidden
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
type SystemNotificationCommandRunnerWithOutput,
|
|
6
6
|
type SystemNotificationsConfig,
|
|
7
7
|
} from './framework-menu-system-notifications-types';
|
|
8
|
-
import { resolveBlockedDialogEnabled } from './framework-menu-system-notifications-macos-dialog';
|
|
8
|
+
import { resolveBlockedDialogEnabled } from './framework-menu-system-notifications-macos-dialog-enabled';
|
|
9
9
|
import { emitMacOsBannerStage } from './framework-menu-system-notifications-macos-banner-stage';
|
|
10
10
|
import { emitMacOsBlockedDialogStage } from './framework-menu-system-notifications-macos-blocked-stage';
|
|
11
11
|
import { finalizeMacOsNotificationDelivery } from './framework-menu-system-notifications-macos-result';
|
|
@@ -13,6 +13,21 @@ import { finalizeMacOsNotificationDelivery } from './framework-menu-system-notif
|
|
|
13
13
|
export { runSystemCommand, runSystemCommandWithOutput } from './framework-menu-system-notifications-macos-runner';
|
|
14
14
|
export { resolveBlockedDialogEnabled } from './framework-menu-system-notifications-macos-dialog';
|
|
15
15
|
|
|
16
|
+
const shouldSkipMacOsBannerForInteractiveBlockedDialog = (params: {
|
|
17
|
+
event: PumukiCriticalNotificationEvent;
|
|
18
|
+
repoRoot?: string;
|
|
19
|
+
config: SystemNotificationsConfig;
|
|
20
|
+
env: NodeJS.ProcessEnv;
|
|
21
|
+
}): boolean => {
|
|
22
|
+
if (params.event.kind !== 'gate.blocked') {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (typeof params.repoRoot !== 'string') {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return resolveBlockedDialogEnabled({ env: params.env, config: params.config });
|
|
29
|
+
};
|
|
30
|
+
|
|
16
31
|
export const deliverMacOsNotification = (params: {
|
|
17
32
|
event: PumukiCriticalNotificationEvent;
|
|
18
33
|
payload: Parameters<typeof emitMacOsBannerStage>[0]['payload'];
|
|
@@ -29,11 +44,20 @@ export const deliverMacOsNotification = (params: {
|
|
|
29
44
|
nowMs: number;
|
|
30
45
|
}) => void;
|
|
31
46
|
}): SystemNotificationEmitResult => {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
47
|
+
const skipBanner = shouldSkipMacOsBannerForInteractiveBlockedDialog({
|
|
48
|
+
event: params.event,
|
|
49
|
+
repoRoot: params.repoRoot,
|
|
50
|
+
config: params.config,
|
|
51
|
+
env: params.env,
|
|
35
52
|
});
|
|
36
53
|
|
|
54
|
+
const bannerResult = skipBanner
|
|
55
|
+
? { delivered: true as const, reason: 'delivered' as const }
|
|
56
|
+
: emitMacOsBannerStage({
|
|
57
|
+
payload: params.payload,
|
|
58
|
+
runCommand: params.runCommand,
|
|
59
|
+
});
|
|
60
|
+
|
|
37
61
|
emitMacOsBlockedDialogStage({
|
|
38
62
|
event: params.event,
|
|
39
63
|
repoRoot: params.repoRoot,
|