Address Codex P1 + Greptile P2:
- Move config validation before the restart attempt so invalid config
is caught in the stop→start path (not just the already-loaded path)
- Derive service.loaded from actual isLoaded() after restart instead
of hardcoded true
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: HCL <chenglunhu@gmail.com>
After `gateway stop` (which runs `launchctl bootout`), `gateway start`
checks `isLoaded` → false → prints "not loaded" hints and exits.
The service is never re-bootstrapped, so `start` cannot recover from
`stop` — only `gateway install` works.
Root cause: src/cli/daemon-cli/lifecycle-core.ts:208-217 — runServiceStart
calls handleServiceNotLoaded which only prints hints, never attempts
service.restart() (which already handles bootstrap via
bootstrapLaunchAgentOrThrow at launchd.ts:598).
Fix: when service is not loaded, attempt service.restart() first (which
handles re-bootstrapping on all platforms). If restart fails (e.g. plist
was deleted, not just booted out), fall back to the existing hints.
The restart path is already proven: restartLaunchAgent (launchd.ts:556)
handles "not loaded" via bootstrapLaunchAgentOrThrow. This fix routes
the start command through the same recovery path.
Closes#53878
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: HCL <chenglunhu@gmail.com>
Regeneration-Prompt: |
Current origin/main fails src/cli/program/preaction.test.ts because the
test asserts on process.title directly inside Vitest, where that runtime
interaction is not stable enough to observe the write reliably. Keep the
production preaction behavior unchanged. Make the test verify that the
hook assigns the expected title by wrapping process.title with a local
getter/setter during each test and restoring the original descriptor
afterward so other tests keep the real process object behavior.
1. Narrow loadConfigForInstall() to catch only INVALID_CONFIG errors,
letting real failures (fs permission, OOM) propagate.
2. Assert allow array is properly cleaned in stale-cleanup test.
3. Add comment clarifying version-resolution is already addressed via
the shared VERSION constant.
4. Run cleanStaleMatrixPluginConfig() during install so
persistPluginInstall() → writeConfigFile() does not fail validation
on stale Matrix load paths.
Previously, `--at` with an offset-less ISO datetime (e.g. `2026-03-23T23:00:00`)
was always interpreted as UTC, even when `--tz` was provided. This caused one-shot
jobs to fire at the wrong time.
Changes:
- `parseAt()` now accepts an optional `tz` parameter
- When `--tz` is provided with `--at`, offset-less datetimes are interpreted in
that IANA timezone using Intl.DateTimeFormat
- Datetimes with explicit offsets (e.g. `+01:00`, `Z`) are unaffected
- Removed the guard in cron-edit that blocked `--tz` with `--at`
- Updated `--at` help text to mention `--tz` support
- Added 2 tests verifying timezone resolution and offset preservation
- Use hasOwnProperty + isBlockedObjectKey in isConfiguredAuthPlugin to
prevent __proto__/constructor/prototype keys from matching config
- Sanitize plugin IDs with sanitizeForLog in ambiguity error messages
- Add regression test for __proto__ plugin ID