jettypod 4.4.118 → 4.4.121
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/.env +4 -3
- package/Cargo.lock +6450 -0
- package/Cargo.toml +35 -0
- package/README.md +5 -1
- package/TAURI-MIGRATION-PLAN.md +840 -0
- package/apps/dashboard/app/connect-claude/page.tsx +5 -6
- package/apps/dashboard/app/decision/[id]/page.tsx +63 -58
- package/apps/dashboard/app/demo/gates/page.tsx +43 -45
- package/apps/dashboard/app/design-system/page.tsx +868 -0
- package/apps/dashboard/app/globals.css +80 -4
- package/apps/dashboard/app/install-claude/page.tsx +4 -6
- package/apps/dashboard/app/login/page.tsx +72 -54
- package/apps/dashboard/app/page.tsx +101 -48
- package/apps/dashboard/app/settings/page.tsx +61 -13
- package/apps/dashboard/app/signup/page.tsx +242 -0
- package/apps/dashboard/app/subscribe/page.tsx +0 -2
- package/apps/dashboard/app/tests/page.tsx +37 -4
- package/apps/dashboard/app/welcome/page.tsx +13 -16
- package/apps/dashboard/app/work/[id]/page.tsx +117 -118
- package/apps/dashboard/app/work/[id]/proof/page.tsx +1489 -0
- package/apps/dashboard/components/AppShell.tsx +92 -85
- package/apps/dashboard/components/CardMenu.tsx +45 -12
- package/apps/dashboard/components/ClaudePanel.tsx +771 -850
- package/apps/dashboard/components/ClaudePanelInput.tsx +43 -15
- package/apps/dashboard/components/ConnectClaudeScreen.tsx +17 -34
- package/apps/dashboard/components/CopyableId.tsx +3 -4
- package/apps/dashboard/components/DetailReviewActions.tsx +100 -0
- package/apps/dashboard/components/DragContext.tsx +134 -63
- package/apps/dashboard/components/DraggableCard.tsx +3 -5
- package/apps/dashboard/components/DropZone.tsx +6 -7
- package/apps/dashboard/components/EditableDetailDescription.tsx +7 -13
- package/apps/dashboard/components/EditableDetailTitle.tsx +6 -13
- package/apps/dashboard/components/EditableTitle.tsx +26 -7
- package/apps/dashboard/components/ElapsedTimer.tsx +66 -0
- package/apps/dashboard/components/EpicGroup.tsx +359 -0
- package/apps/dashboard/components/GateCard.tsx +79 -17
- package/apps/dashboard/components/GateChoiceCard.tsx +15 -18
- package/apps/dashboard/components/InstallClaudeScreen.tsx +15 -32
- package/apps/dashboard/components/JettyLoader.tsx +37 -0
- package/apps/dashboard/components/KanbanBoard.tsx +368 -958
- package/apps/dashboard/components/KanbanCard.tsx +740 -0
- package/apps/dashboard/components/LazyCard.tsx +62 -0
- package/apps/dashboard/components/LazyMarkdown.tsx +11 -0
- package/apps/dashboard/components/MainNav.tsx +38 -73
- package/apps/dashboard/components/MessageBlock.tsx +468 -0
- package/apps/dashboard/components/ModeStartCard.tsx +15 -16
- package/apps/dashboard/components/OnboardingWelcome.tsx +213 -0
- package/apps/dashboard/components/PlaceholderCard.tsx +3 -4
- package/apps/dashboard/components/ProjectSwitcher.tsx +30 -30
- package/apps/dashboard/components/PrototypeTimeline.tsx +72 -51
- package/apps/dashboard/components/RealTimeKanbanWrapper.tsx +406 -388
- package/apps/dashboard/components/RealTimeTestsWrapper.tsx +373 -235
- package/apps/dashboard/components/ReviewFooter.tsx +139 -0
- package/apps/dashboard/components/SessionList.tsx +19 -19
- package/apps/dashboard/components/SubscribeContent.tsx +91 -47
- package/apps/dashboard/components/TestTree.tsx +16 -16
- package/apps/dashboard/components/TipCard.tsx +16 -17
- package/apps/dashboard/components/Toast.tsx +5 -6
- package/apps/dashboard/components/TypeIcon.tsx +55 -0
- package/apps/dashboard/components/ViewModeToolbar.tsx +104 -0
- package/apps/dashboard/components/WaveCompletionAnimation.tsx +52 -65
- package/apps/dashboard/components/WelcomeScreen.tsx +19 -35
- package/apps/dashboard/components/WorkItemHeader.tsx +4 -5
- package/apps/dashboard/components/WorkItemTree.tsx +11 -32
- package/apps/dashboard/components/settings/AccountSection.tsx +55 -35
- package/apps/dashboard/components/settings/AiContextSection.tsx +89 -0
- package/apps/dashboard/components/settings/ContextDocumentsSection.tsx +317 -0
- package/apps/dashboard/components/settings/EnvVarsSection.tsx +74 -152
- package/apps/dashboard/components/settings/GeneralSection.tsx +162 -56
- package/apps/dashboard/components/settings/ProjectStackSection.tsx +948 -0
- package/apps/dashboard/components/settings/SettingsLayout.tsx +4 -5
- package/apps/dashboard/components/ui/Button.tsx +104 -0
- package/apps/dashboard/components/ui/Input.tsx +78 -0
- package/apps/dashboard/components.json +1 -1
- package/apps/dashboard/contexts/ClaudeSessionContext.tsx +711 -418
- package/apps/dashboard/contexts/ConnectionStatusContext.tsx +25 -5
- package/apps/dashboard/contexts/UsageContext.tsx +87 -32
- package/apps/dashboard/dev.sh +35 -0
- package/apps/dashboard/eslint.config.mjs +9 -9
- package/apps/dashboard/hooks/useKanbanAnimation.ts +29 -0
- package/apps/dashboard/hooks/useKanbanUndo.ts +83 -0
- package/apps/dashboard/hooks/useWebSocket.ts +138 -83
- package/apps/dashboard/index.html +73 -0
- package/apps/dashboard/lib/constants.ts +43 -0
- package/apps/dashboard/lib/data-bridge.ts +722 -0
- package/apps/dashboard/lib/db.ts +69 -1265
- package/apps/dashboard/lib/environment-config.ts +173 -0
- package/apps/dashboard/lib/environment-verification.ts +119 -0
- package/apps/dashboard/lib/kanban-utils.ts +270 -0
- package/apps/dashboard/lib/proof-run.ts +495 -0
- package/apps/dashboard/lib/proof-scenario-runner.ts +346 -0
- package/apps/dashboard/lib/run-migrations.js +27 -2
- package/apps/dashboard/lib/service-recovery.ts +326 -0
- package/apps/dashboard/lib/session-state-machine.ts +1 -0
- package/apps/dashboard/lib/session-state-utils.ts +0 -164
- package/apps/dashboard/lib/session-stream-manager.ts +308 -134
- package/apps/dashboard/lib/shadows.ts +7 -0
- package/apps/dashboard/lib/stream-manager-registry.ts +46 -6
- package/apps/dashboard/lib/tauri-bridge.ts +102 -0
- package/apps/dashboard/lib/tauri.ts +106 -0
- package/apps/dashboard/lib/utils.ts +6 -0
- package/apps/dashboard/next-env.d.ts +1 -1
- package/apps/dashboard/package.json +21 -32
- package/apps/dashboard/public/bug-icon.png +0 -0
- package/apps/dashboard/public/buoy-icon.png +0 -0
- package/apps/dashboard/public/fonts/Satoshi-Variable.woff2 +0 -0
- package/apps/dashboard/public/fonts/Satoshi-VariableItalic.woff2 +0 -0
- package/apps/dashboard/public/in-flight-seagull.png +0 -0
- package/apps/dashboard/public/jetty-icon-loading-alt.svg +11 -0
- package/apps/dashboard/public/jetty-icon-loading.svg +11 -0
- package/apps/dashboard/public/jettypod_logo.png +0 -0
- package/apps/dashboard/public/pier-icon.png +0 -0
- package/apps/dashboard/public/star-icon.png +0 -0
- package/apps/dashboard/public/wrench-icon.png +0 -0
- package/apps/dashboard/scripts/tauri-build.js +228 -0
- package/apps/dashboard/scripts/upload-tauri-to-r2.js +125 -0
- package/apps/dashboard/scripts/ws-server.js +191 -0
- package/apps/dashboard/src/main.tsx +12 -0
- package/apps/dashboard/src/router.tsx +107 -0
- package/apps/dashboard/src/vite-env.d.ts +1 -0
- package/apps/dashboard/tsconfig.json +7 -12
- package/apps/dashboard/tsconfig.tsbuildinfo +1 -1
- package/apps/dashboard/vite.config.ts +33 -0
- package/apps/update-server/src/index.ts +228 -80
- package/claude-hooks/global-guardrails.js +14 -13
- package/crates/jettypod-cli/Cargo.toml +19 -0
- package/crates/jettypod-cli/src/commands.rs +1249 -0
- package/crates/jettypod-cli/src/main.rs +595 -0
- package/crates/jettypod-core/Cargo.toml +26 -0
- package/crates/jettypod-core/build.rs +98 -0
- package/crates/jettypod-core/migrations/V1__baseline.sql +197 -0
- package/crates/jettypod-core/migrations/V2__work_items_indexes.sql +6 -0
- package/crates/jettypod-core/migrations/V3__qa_steps.sql +2 -0
- package/crates/jettypod-core/src/auth.rs +294 -0
- package/crates/jettypod-core/src/config.rs +397 -0
- package/crates/jettypod-core/src/db/mod.rs +507 -0
- package/crates/jettypod-core/src/db/recovery.rs +114 -0
- package/crates/jettypod-core/src/db/startup.rs +101 -0
- package/crates/jettypod-core/src/db/validate.rs +149 -0
- package/crates/jettypod-core/src/error.rs +76 -0
- package/crates/jettypod-core/src/git.rs +458 -0
- package/crates/jettypod-core/src/lib.rs +20 -0
- package/crates/jettypod-core/src/sessions.rs +625 -0
- package/crates/jettypod-core/src/skills.rs +556 -0
- package/crates/jettypod-core/src/work.rs +1086 -0
- package/crates/jettypod-core/src/worktree.rs +628 -0
- package/crates/jettypod-core/src/ws.rs +767 -0
- package/cucumber-test.cjs +6 -0
- package/cucumber.js +9 -3
- package/docs/COMMAND_REFERENCE.md +34 -0
- package/hooks/post-checkout +32 -75
- package/hooks/post-merge +111 -10
- package/jest.setup.js +1 -0
- package/jettypod.js +145 -116
- package/lib/bdd-preflight.js +96 -0
- package/lib/chore-taxonomy.js +33 -10
- package/lib/database.js +36 -16
- package/lib/db-watcher.js +1 -1
- package/lib/git-hooks/pre-commit +1 -1
- package/lib/jettypod-backup.js +27 -4
- package/lib/merge-lock.js +111 -253
- package/lib/migrations/027-plan-at-creation-column.js +3 -1
- package/lib/migrations/029-remove-autoincrement.js +307 -0
- package/lib/migrations/029-rename-corrupted-to-cleaned.js +149 -0
- package/lib/migrations/030-rejection-round-columns.js +54 -0
- package/lib/migrations/031-session-isolation-index.js +17 -0
- package/lib/migrations/index.js +47 -4
- package/lib/schema.js +10 -5
- package/lib/seed-onboarding.js +1 -1
- package/lib/update-command/index.js +9 -175
- package/lib/work-commands/index.js +144 -19
- package/lib/work-tracking/index.js +148 -27
- package/lib/worktree-diagnostics.js +16 -16
- package/lib/worktree-facade.js +1 -1
- package/lib/worktree-manager.js +8 -8
- package/lib/worktree-reconciler.js +5 -5
- package/package.json +9 -2
- package/scripts/ndjson-to-cucumber-json.js +152 -0
- package/scripts/postinstall.js +25 -0
- package/skills-templates/bug-mode/SKILL.md +79 -20
- package/skills-templates/bug-planning/SKILL.md +25 -29
- package/skills-templates/chore-mode/SKILL.md +171 -69
- package/skills-templates/chore-mode/verification.js +51 -10
- package/skills-templates/chore-planning/SKILL.md +47 -18
- package/skills-templates/design-system-selection/SKILL.md +273 -0
- package/skills-templates/epic-planning/SKILL.md +82 -48
- package/skills-templates/external-transition/SKILL.md +47 -47
- package/skills-templates/feature-planning/SKILL.md +173 -74
- package/skills-templates/production-mode/SKILL.md +69 -49
- package/skills-templates/request-routing/SKILL.md +4 -4
- package/skills-templates/simple-improvement/SKILL.md +74 -29
- package/skills-templates/speed-mode/SKILL.md +217 -141
- package/skills-templates/stable-mode/SKILL.md +148 -89
- package/apps/dashboard/README.md +0 -36
- package/apps/dashboard/app/api/claude/[workItemId]/message/route.ts +0 -386
- package/apps/dashboard/app/api/claude/[workItemId]/pin/route.ts +0 -24
- package/apps/dashboard/app/api/claude/[workItemId]/route.ts +0 -167
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/content/route.ts +0 -52
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/message/route.ts +0 -378
- package/apps/dashboard/app/api/claude/sessions/[sessionId]/pin/route.ts +0 -24
- package/apps/dashboard/app/api/claude/sessions/cleanup/route.ts +0 -34
- package/apps/dashboard/app/api/claude/sessions/route.ts +0 -184
- package/apps/dashboard/app/api/decisions/[id]/route.ts +0 -25
- package/apps/dashboard/app/api/internal/set-project/route.ts +0 -17
- package/apps/dashboard/app/api/kanban/route.ts +0 -15
- package/apps/dashboard/app/api/settings/env-vars/route.ts +0 -125
- package/apps/dashboard/app/api/settings/general/route.ts +0 -21
- package/apps/dashboard/app/api/tests/route.ts +0 -9
- package/apps/dashboard/app/api/tests/run/route.ts +0 -82
- package/apps/dashboard/app/api/tests/run/stream/route.ts +0 -71
- package/apps/dashboard/app/api/tests/undefined/route.ts +0 -9
- package/apps/dashboard/app/api/usage/route.ts +0 -17
- package/apps/dashboard/app/api/work/[id]/description/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/epic/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/order/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/status/route.ts +0 -21
- package/apps/dashboard/app/api/work/[id]/title/route.ts +0 -21
- package/apps/dashboard/app/layout.tsx +0 -43
- package/apps/dashboard/components/UpgradeBanner.tsx +0 -29
- package/apps/dashboard/electron/ipc-handlers.js +0 -1028
- package/apps/dashboard/electron/main.js +0 -2124
- package/apps/dashboard/electron/preload.js +0 -123
- package/apps/dashboard/electron/session-manager.js +0 -141
- package/apps/dashboard/electron-builder.config.js +0 -357
- package/apps/dashboard/hooks/useClaudeSessions.ts +0 -299
- package/apps/dashboard/lib/claude-process-manager.ts +0 -492
- package/apps/dashboard/lib/db-bridge.ts +0 -282
- package/apps/dashboard/lib/prototypes.ts +0 -202
- package/apps/dashboard/lib/test-results-db.ts +0 -307
- package/apps/dashboard/lib/tests.ts +0 -282
- package/apps/dashboard/next.config.js +0 -50
- package/apps/dashboard/postcss.config.mjs +0 -7
- package/apps/dashboard/public/file.svg +0 -1
- package/apps/dashboard/public/globe.svg +0 -1
- package/apps/dashboard/public/next.svg +0 -1
- package/apps/dashboard/public/vercel.svg +0 -1
- package/apps/dashboard/public/window.svg +0 -1
- package/apps/dashboard/scripts/download-node.js +0 -104
- package/apps/dashboard/scripts/upload-to-r2.js +0 -89
- package/docs/bdd-guidance.md +0 -390
package/cucumber.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
1
3
|
module.exports = {
|
|
2
4
|
default: {
|
|
3
|
-
require: ['features/**/steps.js', 'features/**/simple-steps.js', 'features/**/*.steps.js'],
|
|
4
|
-
format: [
|
|
5
|
-
|
|
5
|
+
require: ['features/support/*.js', 'features/**/steps.js', 'features/**/simple-steps.js', 'features/**/*.steps.js'],
|
|
6
|
+
format: [
|
|
7
|
+
'progress',
|
|
8
|
+
`json:${path.resolve(__dirname, 'cucumber-results.json')}`,
|
|
9
|
+
`message:${path.resolve(__dirname, 'cucumber-results.ndjson')}`,
|
|
10
|
+
`rerun:${path.resolve(__dirname, '@rerun.txt')}`,
|
|
11
|
+
]
|
|
6
12
|
}
|
|
7
13
|
};
|
|
@@ -98,8 +98,36 @@ jettypod project discover complete \
|
|
|
98
98
|
|
|
99
99
|
## Work Item Management
|
|
100
100
|
|
|
101
|
+
### `jettypod work create --from=<filepath>`
|
|
102
|
+
|
|
103
|
+
Create any work item type from a JSON file. **This is the preferred method** — it avoids shell quoting issues and is truncation-safe (a truncated file path errors immediately instead of hanging).
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Write JSON file first, then create
|
|
107
|
+
jettypod work create --from=/tmp/jettypod-create.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**JSON file format:**
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"type": "feature",
|
|
114
|
+
"title": "Login Form",
|
|
115
|
+
"description": "User login UI component",
|
|
116
|
+
"parent": 5,
|
|
117
|
+
"mode": "speed",
|
|
118
|
+
"needsDiscovery": false
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Required fields:** `type` (epic/feature/chore/bug), `title`
|
|
123
|
+
**Optional fields:** `description`, `parent` (ID), `mode` (speed/stable/production), `needsDiscovery` (boolean)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
101
127
|
### `jettypod work create epic <title> [description] [flags]`
|
|
102
128
|
|
|
129
|
+
> **Prefer `--from` (above)** for Claude Code usage — positional args risk shell hangs from truncated quotes.
|
|
130
|
+
|
|
103
131
|
Create a new epic.
|
|
104
132
|
|
|
105
133
|
```bash
|
|
@@ -126,6 +154,8 @@ jettypod work create epic "Real-time Updates" "Live data sync" --needs-discovery
|
|
|
126
154
|
|
|
127
155
|
### `jettypod work create feature <title> [description] [flags]`
|
|
128
156
|
|
|
157
|
+
> **Prefer `--from` (above)** for Claude Code usage — positional args risk shell hangs from truncated quotes.
|
|
158
|
+
|
|
129
159
|
Create a new feature.
|
|
130
160
|
|
|
131
161
|
```bash
|
|
@@ -155,6 +185,8 @@ jettypod work create feature "Dashboard" "User dashboard" --mode=stable
|
|
|
155
185
|
|
|
156
186
|
### `jettypod work create chore <title> [description] [flags]`
|
|
157
187
|
|
|
188
|
+
> **Prefer `--from` (above)** for Claude Code usage — positional args risk shell hangs from truncated quotes.
|
|
189
|
+
|
|
158
190
|
Create a chore (non-feature work).
|
|
159
191
|
|
|
160
192
|
```bash
|
|
@@ -170,6 +202,8 @@ jettypod work create chore "Refactor auth module" --parent=5
|
|
|
170
202
|
|
|
171
203
|
### `jettypod work create bug <title> [description] [flags]`
|
|
172
204
|
|
|
205
|
+
> **Prefer `--from` (above)** for Claude Code usage — positional args risk shell hangs from truncated quotes.
|
|
206
|
+
|
|
173
207
|
Create a bug.
|
|
174
208
|
|
|
175
209
|
```bash
|
package/hooks/post-checkout
CHANGED
|
@@ -7,96 +7,53 @@
|
|
|
7
7
|
* 2. Imports database snapshots after checkout
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const { importAll } = require('jettypod/lib/db-import');
|
|
11
|
-
const { walCheckpoint } = require('jettypod/lib/database');
|
|
12
10
|
const { execSync } = require('child_process');
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
const cwd = process.cwd();
|
|
12
|
+
const cwd = process.cwd();
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
// Prevent checking out default branch in JettyPod worktrees
|
|
15
|
+
if (cwd.includes('.jettypod-work')) {
|
|
16
|
+
try {
|
|
17
|
+
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
18
|
+
encoding: 'utf8',
|
|
19
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
20
|
+
}).trim();
|
|
21
|
+
|
|
22
|
+
// Detect default branch
|
|
23
|
+
let defaultBranch;
|
|
19
24
|
try {
|
|
20
|
-
|
|
21
|
-
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {
|
|
25
|
+
defaultBranch = execSync('git symbolic-ref refs/remotes/origin/HEAD', {
|
|
22
26
|
encoding: 'utf8',
|
|
23
27
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
24
|
-
}).trim();
|
|
25
|
-
|
|
26
|
-
// Detect default branch
|
|
27
|
-
let defaultBranch;
|
|
28
|
+
}).trim().replace('refs/remotes/origin/', '');
|
|
29
|
+
} catch {
|
|
28
30
|
try {
|
|
29
|
-
|
|
30
|
-
defaultBranch =
|
|
31
|
-
encoding: 'utf8',
|
|
32
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
33
|
-
}).trim().replace('refs/remotes/origin/', '');
|
|
31
|
+
execSync('git rev-parse --verify main', { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
32
|
+
defaultBranch = 'main';
|
|
34
33
|
} catch {
|
|
35
|
-
// Fallback: check which common branch names exist
|
|
36
34
|
try {
|
|
37
|
-
execSync('git rev-parse --verify
|
|
38
|
-
defaultBranch = '
|
|
35
|
+
execSync('git rev-parse --verify master', { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
36
|
+
defaultBranch = 'master';
|
|
39
37
|
} catch {
|
|
40
|
-
|
|
41
|
-
execSync('git rev-parse --verify master', { stdio: ['pipe', 'pipe', 'pipe'] });
|
|
42
|
-
defaultBranch = 'master';
|
|
43
|
-
} catch {
|
|
44
|
-
// Can't determine default branch - skip check
|
|
45
|
-
defaultBranch = null;
|
|
46
|
-
}
|
|
38
|
+
defaultBranch = null;
|
|
47
39
|
}
|
|
48
40
|
}
|
|
41
|
+
}
|
|
49
42
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
56
|
-
console.error('');
|
|
57
|
-
console.error(`You are in a JettyPod worktree for isolated work.`);
|
|
58
|
-
console.error(`Checking out ${defaultBranch} in a worktree bypasses the merge workflow.`);
|
|
59
|
-
console.error('');
|
|
60
|
-
console.error('To merge your changes:');
|
|
61
|
-
console.error(' 1. Commit your changes: git add . && git commit -m "..."');
|
|
62
|
-
console.error(' 2. Use JettyPod merge: jettypod work merge');
|
|
63
|
-
console.error('');
|
|
64
|
-
console.error('This ensures proper worktree cleanup and database updates.');
|
|
65
|
-
console.error('');
|
|
66
|
-
console.error('Reverting checkout...');
|
|
67
|
-
console.error('');
|
|
68
|
-
|
|
69
|
-
// Revert to previous branch
|
|
70
|
-
try {
|
|
71
|
-
execSync('git checkout -', { stdio: 'inherit' });
|
|
72
|
-
} catch (revertErr) {
|
|
73
|
-
console.error('Failed to revert checkout. You may need to manually switch branches.');
|
|
74
|
-
}
|
|
43
|
+
if (defaultBranch && currentBranch === defaultBranch) {
|
|
44
|
+
console.error('\n❌ Cannot checkout default branch in worktree');
|
|
45
|
+
console.error(`Checking out ${defaultBranch} bypasses the merge workflow.\n`);
|
|
46
|
+
console.error('To merge: jettypod work merge\n');
|
|
47
|
+
console.error('Reverting checkout...\n');
|
|
75
48
|
|
|
76
|
-
|
|
49
|
+
try {
|
|
50
|
+
execSync('git checkout -', { stdio: 'inherit' });
|
|
51
|
+
} catch (revertErr) {
|
|
52
|
+
console.error('Failed to revert. Manually switch branches.');
|
|
77
53
|
}
|
|
78
|
-
|
|
79
|
-
// If we can't determine the branch, allow the checkout
|
|
80
|
-
// (better to be permissive than block legitimate operations)
|
|
54
|
+
process.exit(1);
|
|
81
55
|
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// SECOND: Checkpoint WAL before importing to prevent corruption
|
|
85
|
-
// This flushes any pending writes to the main database file
|
|
86
|
-
try {
|
|
87
|
-
await walCheckpoint();
|
|
88
|
-
} catch (err) {
|
|
89
|
-
// Checkpoint failure shouldn't block - just log and continue
|
|
90
|
-
console.error('Post-checkout hook warning: WAL checkpoint failed:', err.message);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// THIRD: Import database snapshots
|
|
94
|
-
try {
|
|
95
|
-
await importAll();
|
|
96
|
-
process.exit(0);
|
|
97
56
|
} catch (err) {
|
|
98
|
-
//
|
|
99
|
-
console.error('Post-checkout hook warning:', err.message);
|
|
100
|
-
process.exit(0);
|
|
57
|
+
// Can't determine branch - allow checkout
|
|
101
58
|
}
|
|
102
|
-
}
|
|
59
|
+
}
|
package/hooks/post-merge
CHANGED
|
@@ -1,17 +1,118 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// JettyPod Git Hook: post-merge
|
|
4
|
+
// Backs up database to .jettypod-backup/ when merging to main
|
|
5
|
+
// Uses --no-verify to bypass pre-commit tests for data-only commits
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { execSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
const jettypodDir = path.join(process.cwd(), '.jettypod');
|
|
12
|
+
const backupDir = path.join(process.cwd(), '.jettypod-backup');
|
|
13
|
+
|
|
14
|
+
// Backup database and commit
|
|
15
|
+
function backupDatabase() {
|
|
16
|
+
if (!fs.existsSync(jettypodDir)) {
|
|
17
|
+
return; // No JettyPod directory, skip backup
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Only backup on main/master branch
|
|
21
|
+
let currentBranch;
|
|
6
22
|
try {
|
|
7
|
-
|
|
8
|
-
|
|
23
|
+
currentBranch = execSync('git branch --show-current', { encoding: 'utf-8' }).trim();
|
|
24
|
+
} catch {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (currentBranch !== 'main' && currentBranch !== 'master') {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log('\n💾 Backing up database...\n');
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
// Ensure backup directory exists
|
|
36
|
+
if (!fs.existsSync(backupDir)) {
|
|
37
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Backup work.db using sqlite3 .backup command
|
|
41
|
+
// CRITICAL: fs.copyFileSync does NOT work with WAL mode - it only copies
|
|
42
|
+
// the base .db file, missing all data in the -wal file. sqlite3 .backup
|
|
43
|
+
// reads the logical database (including WAL) and writes a clean standalone file.
|
|
44
|
+
const sourcePath = path.join(jettypodDir, 'work.db');
|
|
45
|
+
const backupPath = path.join(backupDir, 'work.db');
|
|
9
46
|
|
|
10
|
-
|
|
11
|
-
|
|
47
|
+
if (!fs.existsSync(sourcePath)) {
|
|
48
|
+
console.log('⚠️ No work.db found, skipping backup\n');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
execSync(`sqlite3 "${sourcePath}" ".backup '${backupPath}'"`, {
|
|
53
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// SAFETY: Validate backup didn't lose data
|
|
57
|
+
// If an existing backup has significantly more items, refuse to overwrite
|
|
58
|
+
const newCount = parseInt(execSync(
|
|
59
|
+
`sqlite3 "${backupPath}" "SELECT count(*) FROM work_items"`,
|
|
60
|
+
{ encoding: 'utf-8', stdio: 'pipe' }
|
|
61
|
+
).trim()) || 0;
|
|
62
|
+
|
|
63
|
+
if (newCount < 2) {
|
|
64
|
+
console.log('⚠️ Backup has fewer than 2 items - likely corrupted, skipping commit\n');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Check against git's previous version of the backup
|
|
69
|
+
try {
|
|
70
|
+
const oldCount = parseInt(execSync(
|
|
71
|
+
`git show HEAD:.jettypod-backup/work.db 2>/dev/null | sqlite3 "" "SELECT count(*) FROM work_items"`,
|
|
72
|
+
{ encoding: 'utf-8', stdio: 'pipe' }
|
|
73
|
+
).trim()) || 0;
|
|
74
|
+
|
|
75
|
+
if (oldCount > 0 && newCount < oldCount * 0.5) {
|
|
76
|
+
console.log(`⚠️ Backup shrank from ${oldCount} to ${newCount} items (>50% loss) - refusing to commit\n`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
// No previous backup in git or can't read it - proceed
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Stage the backup file (force-add because .jettypod-backup is gitignored
|
|
84
|
+
// to prevent worktree symlink corruption, but backups must be committed)
|
|
85
|
+
execSync(`git add -f "${backupPath}"`, {
|
|
86
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Check if there are any staged changes
|
|
90
|
+
try {
|
|
91
|
+
execSync('git diff --cached --quiet', {
|
|
92
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
93
|
+
});
|
|
94
|
+
// No staged changes, nothing to commit
|
|
95
|
+
console.log('✅ Database backup unchanged\n');
|
|
96
|
+
return;
|
|
97
|
+
} catch {
|
|
98
|
+
// Has staged changes, continue to commit
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
execSync('git commit --no-verify -m "chore: Update database backup"', {
|
|
102
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Push the backup commit
|
|
106
|
+
execSync('git push', {
|
|
107
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
console.log('✅ Database backed up and pushed\n');
|
|
12
111
|
} catch (err) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
process.exit(0);
|
|
112
|
+
console.error('⚠️ Database backup failed:', err.message);
|
|
113
|
+
// Don't block - backup is important but not critical
|
|
16
114
|
}
|
|
17
|
-
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Main
|
|
118
|
+
backupDatabase();
|
package/jest.setup.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
process.env.NODE_ENV = 'test';
|