@getjack/jack 0.1.28 → 0.1.30
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/package.json +1 -1
- package/src/commands/cd.ts +163 -0
- package/src/commands/clone.ts +112 -68
- package/src/commands/domain.ts +506 -0
- package/src/commands/domains.ts +215 -0
- package/src/commands/down.ts +18 -12
- package/src/commands/hack.ts +185 -8
- package/src/commands/init.ts +52 -1
- package/src/commands/link.ts +25 -43
- package/src/commands/logs.ts +2 -2
- package/src/commands/mcp.ts +74 -3
- package/src/commands/new.ts +48 -54
- package/src/commands/projects.ts +53 -10
- package/src/commands/secrets.ts +5 -1
- package/src/commands/services.ts +16 -4
- package/src/commands/shell-init.ts +43 -0
- package/src/commands/ship.ts +2 -11
- package/src/commands/skills.ts +335 -0
- package/src/commands/update.ts +31 -0
- package/src/commands/upgrade.ts +14 -0
- package/src/index.ts +116 -24
- package/src/lib/agent-integration.ts +1 -2
- package/src/lib/agents.ts +2 -2
- package/src/lib/auth/login-flow.ts +1 -1
- package/src/lib/clone-core.ts +252 -0
- package/src/lib/config.ts +22 -0
- package/src/lib/control-plane.ts +31 -5
- package/src/lib/fuzzy.ts +93 -0
- package/src/lib/managed-deploy.ts +4 -1
- package/src/lib/managed-down.ts +20 -5
- package/src/lib/output.ts +90 -9
- package/src/lib/picker.ts +406 -0
- package/src/lib/project-detection.ts +5 -2
- package/src/lib/project-list.ts +66 -5
- package/src/lib/project-operations.ts +68 -6
- package/src/lib/prompts.ts +1 -1
- package/src/lib/services/db-execute.ts +8 -1
- package/src/lib/services/db-list.ts +4 -1
- package/src/lib/services/domain-operations.ts +379 -0
- package/src/lib/services/storage-config.ts +1 -5
- package/src/lib/services/storage-delete.ts +1 -1
- package/src/lib/services/storage-info.ts +2 -4
- package/src/lib/services/vectorize-config.ts +1 -5
- package/src/lib/services/vectorize-create.ts +3 -1
- package/src/lib/shell-integration.ts +202 -0
- package/src/lib/telemetry-config.ts +50 -4
- package/src/lib/telemetry.ts +71 -2
- package/src/lib/version-check.ts +1 -3
- package/src/lib/wrangler-config.test.ts +2 -2
- package/src/lib/wrangler-config.ts +1 -1
- package/src/lib/zip-packager.ts +1 -3
- package/src/mcp/tools/index.ts +261 -7
- package/src/templates/index.ts +10 -1
- package/templates/ai-chat/.jack.json +1 -5
- package/templates/ai-chat/public/chat.js +130 -130
- package/templates/ai-chat/src/index.ts +9 -13
- package/templates/ai-chat/src/jack-ai.ts +6 -2
- package/templates/saas/.jack.json +6 -1
- package/templates/saas/src/auth.ts +8 -4
- package/templates/saas/src/client/App.tsx +22 -7
- package/templates/saas/src/client/components/ProtectedRoute.tsx +9 -2
- package/templates/saas/src/client/components/ThemeToggle.tsx +1 -6
- package/templates/saas/src/client/components/ui/accordion.tsx +1 -1
- package/templates/saas/src/client/components/ui/alert-dialog.tsx +2 -2
- package/templates/saas/src/client/components/ui/alert.tsx +2 -2
- package/templates/saas/src/client/components/ui/avatar.tsx +1 -1
- package/templates/saas/src/client/components/ui/badge.tsx +2 -2
- package/templates/saas/src/client/components/ui/breadcrumb.tsx +1 -1
- package/templates/saas/src/client/components/ui/button-group.tsx +2 -2
- package/templates/saas/src/client/components/ui/button.tsx +2 -2
- package/templates/saas/src/client/components/ui/card.tsx +1 -1
- package/templates/saas/src/client/components/ui/carousel.tsx +2 -2
- package/templates/saas/src/client/components/ui/checkbox.tsx +1 -1
- package/templates/saas/src/client/components/ui/command.tsx +2 -2
- package/templates/saas/src/client/components/ui/context-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/dialog.tsx +1 -1
- package/templates/saas/src/client/components/ui/drawer.tsx +1 -1
- package/templates/saas/src/client/components/ui/dropdown-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/empty.tsx +1 -1
- package/templates/saas/src/client/components/ui/field.tsx +2 -2
- package/templates/saas/src/client/components/ui/form.tsx +5 -5
- package/templates/saas/src/client/components/ui/hover-card.tsx +1 -1
- package/templates/saas/src/client/components/ui/input-group.tsx +3 -3
- package/templates/saas/src/client/components/ui/input-otp.tsx +1 -1
- package/templates/saas/src/client/components/ui/input.tsx +1 -1
- package/templates/saas/src/client/components/ui/item.tsx +3 -3
- package/templates/saas/src/client/components/ui/label.tsx +1 -1
- package/templates/saas/src/client/components/ui/menubar.tsx +1 -1
- package/templates/saas/src/client/components/ui/navigation-menu.tsx +1 -1
- package/templates/saas/src/client/components/ui/pagination.tsx +2 -2
- package/templates/saas/src/client/components/ui/popover.tsx +1 -1
- package/templates/saas/src/client/components/ui/progress.tsx +1 -1
- package/templates/saas/src/client/components/ui/radio-group.tsx +1 -1
- package/templates/saas/src/client/components/ui/resizable.tsx +1 -1
- package/templates/saas/src/client/components/ui/scroll-area.tsx +1 -1
- package/templates/saas/src/client/components/ui/select.tsx +1 -1
- package/templates/saas/src/client/components/ui/separator.tsx +1 -1
- package/templates/saas/src/client/components/ui/sheet.tsx +1 -1
- package/templates/saas/src/client/components/ui/sidebar.tsx +4 -4
- package/templates/saas/src/client/components/ui/slider.tsx +1 -1
- package/templates/saas/src/client/components/ui/switch.tsx +1 -1
- package/templates/saas/src/client/components/ui/table.tsx +1 -1
- package/templates/saas/src/client/components/ui/tabs.tsx +1 -1
- package/templates/saas/src/client/components/ui/textarea.tsx +1 -1
- package/templates/saas/src/client/components/ui/toggle-group.tsx +3 -3
- package/templates/saas/src/client/components/ui/toggle.tsx +2 -2
- package/templates/saas/src/client/components/ui/tooltip.tsx +1 -1
- package/templates/saas/src/client/hooks/useSubscription.ts +5 -4
- package/templates/saas/src/client/lib/auth-client.ts +1 -1
- package/templates/saas/src/client/lib/plans.ts +1 -6
- package/templates/saas/src/client/lib/utils.ts +1 -1
- package/templates/saas/src/client/main.tsx +1 -1
- package/templates/saas/src/client/pages/DashboardPage.tsx +41 -9
- package/templates/saas/src/client/pages/ForgotPasswordPage.tsx +11 -2
- package/templates/saas/src/client/pages/HomePage.tsx +11 -2
- package/templates/saas/src/client/pages/LoginPage.tsx +11 -2
- package/templates/saas/src/client/pages/PricingPage.tsx +20 -10
- package/templates/saas/src/client/pages/ResetPasswordPage.tsx +14 -11
- package/templates/saas/src/client/pages/SignupPage.tsx +11 -2
- package/templates/saas/src/index.ts +28 -19
- package/templates/saas/vite.config.ts +1 -1
- package/templates/semantic-search/.jack.json +1 -5
- package/templates/semantic-search/src/index.ts +8 -4
- package/templates/semantic-search/src/jack-ai.ts +6 -2
- package/templates/semantic-search/src/jack-vectorize.ts +5 -1
package/src/commands/new.ts
CHANGED
|
@@ -2,11 +2,17 @@ import { getPreferredLaunchAgent, launchAgent, scanAgents, updateAgent } from ".
|
|
|
2
2
|
import { debug } from "../lib/debug.ts";
|
|
3
3
|
import { getErrorDetails } from "../lib/errors.ts";
|
|
4
4
|
import { isIntentPhrase } from "../lib/intent.ts";
|
|
5
|
-
import {
|
|
5
|
+
import { createReporter, output } from "../lib/output.ts";
|
|
6
6
|
import { createProject } from "../lib/project-operations.ts";
|
|
7
|
+
import {
|
|
8
|
+
detectShell,
|
|
9
|
+
getRcFilePath,
|
|
10
|
+
isInstalled as isShellIntegrationInstalled,
|
|
11
|
+
} from "../lib/shell-integration.ts";
|
|
7
12
|
|
|
8
13
|
export default async function newProject(
|
|
9
14
|
nameOrPhrase?: string,
|
|
15
|
+
pathArg?: string,
|
|
10
16
|
options: {
|
|
11
17
|
template?: string;
|
|
12
18
|
intent?: string;
|
|
@@ -51,20 +57,11 @@ export default async function newProject(
|
|
|
51
57
|
result = await createProject(projectName, {
|
|
52
58
|
template: options.template,
|
|
53
59
|
intent: intentPhrase,
|
|
54
|
-
reporter:
|
|
55
|
-
start: output.start,
|
|
56
|
-
stop: output.stop,
|
|
57
|
-
spinner,
|
|
58
|
-
info: output.info,
|
|
59
|
-
warn: output.warn,
|
|
60
|
-
error: output.error,
|
|
61
|
-
success: output.success,
|
|
62
|
-
box: output.box,
|
|
63
|
-
celebrate: output.celebrate,
|
|
64
|
-
},
|
|
60
|
+
reporter: createReporter(),
|
|
65
61
|
interactive: !isCi,
|
|
66
62
|
managed: options.managed,
|
|
67
63
|
byo: options.byo,
|
|
64
|
+
targetDir: pathArg || undefined,
|
|
68
65
|
});
|
|
69
66
|
} catch (error) {
|
|
70
67
|
const details = getErrorDetails(error);
|
|
@@ -96,63 +93,60 @@ export default async function newProject(
|
|
|
96
93
|
return;
|
|
97
94
|
}
|
|
98
95
|
|
|
99
|
-
|
|
100
|
-
output.info(`Project: ${result.targetDir}`);
|
|
101
|
-
|
|
102
|
-
// Skip agent section entirely if --no-open or env var
|
|
96
|
+
// Skip next steps if --no-open or env var
|
|
103
97
|
if (options.noOpen || process.env.JACK_NO_OPEN === "1") {
|
|
104
98
|
return;
|
|
105
99
|
}
|
|
106
100
|
|
|
107
|
-
//
|
|
101
|
+
// Check if shell integration is installed
|
|
102
|
+
const shell = detectShell();
|
|
103
|
+
const rcFile = getRcFilePath(shell);
|
|
104
|
+
const hasShellIntegration = rcFile ? isShellIntegrationInstalled(rcFile) : false;
|
|
105
|
+
|
|
108
106
|
if (!process.stdout.isTTY || isCi) {
|
|
107
|
+
console.error("");
|
|
108
|
+
console.error(`cd ${result.targetDir}`);
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
//
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
112
|
+
// Auto-open if --open flag (requires agent detection)
|
|
113
|
+
if (options.open) {
|
|
114
|
+
let preferred = await getPreferredLaunchAgent();
|
|
115
|
+
|
|
116
|
+
if (!preferred) {
|
|
117
|
+
const detectionResult = await scanAgents();
|
|
118
|
+
if (detectionResult.detected.length > 0) {
|
|
119
|
+
for (const { id, path, launch } of detectionResult.detected) {
|
|
120
|
+
await updateAgent(id, {
|
|
121
|
+
active: true,
|
|
122
|
+
path,
|
|
123
|
+
detectedAt: new Date().toISOString(),
|
|
124
|
+
launch,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
preferred = await getPreferredLaunchAgent();
|
|
128
128
|
}
|
|
129
|
-
// Use the first detected agent as preferred
|
|
130
|
-
preferred = await getPreferredLaunchAgent();
|
|
131
129
|
}
|
|
132
|
-
}
|
|
133
130
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
131
|
+
if (preferred) {
|
|
132
|
+
const launchResult = await launchAgent(preferred.launch, result.targetDir, {
|
|
133
|
+
projectName: result.projectName,
|
|
134
|
+
url: result.workerUrl,
|
|
135
|
+
});
|
|
136
|
+
if (!launchResult.success) {
|
|
137
|
+
output.warn(`Failed to launch ${preferred.definition.name}`);
|
|
138
|
+
if (launchResult.command?.length) {
|
|
139
|
+
output.info(`Run manually: ${launchResult.command.join(" ")}`);
|
|
140
|
+
}
|
|
144
141
|
}
|
|
142
|
+
return;
|
|
145
143
|
}
|
|
146
|
-
return;
|
|
147
144
|
}
|
|
148
145
|
|
|
149
|
-
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
output.info(`Next: cd ${result.targetDir} && ${preferred.launch.command}`);
|
|
146
|
+
console.error("");
|
|
147
|
+
if (hasShellIntegration) {
|
|
148
|
+
output.success(`Ready in ${result.projectName}`);
|
|
153
149
|
} else {
|
|
154
|
-
console.error(
|
|
155
|
-
output.info("No AI agents detected");
|
|
156
|
-
output.info("Install Claude Code or Codex, then run: jack agents scan");
|
|
150
|
+
console.error(`cd ${result.targetDir}`);
|
|
157
151
|
}
|
|
158
152
|
}
|
package/src/commands/projects.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
|
+
import { fuzzyFilter } from "../lib/fuzzy.ts";
|
|
4
5
|
import { promptSelect } from "../lib/hooks.ts";
|
|
5
6
|
import { error, info, item, output as outputSpinner, success, warn } from "../lib/output.ts";
|
|
6
7
|
import {
|
|
7
8
|
type ProjectListItem,
|
|
8
9
|
STATUS_ICONS,
|
|
10
|
+
type SortOrder,
|
|
9
11
|
buildTagColorMap,
|
|
10
12
|
colors,
|
|
11
13
|
filterByStatus,
|
|
@@ -16,6 +18,7 @@ import {
|
|
|
16
18
|
formatTagsInline,
|
|
17
19
|
groupProjects,
|
|
18
20
|
sortByUpdated,
|
|
21
|
+
sortItems,
|
|
19
22
|
toListItems,
|
|
20
23
|
} from "../lib/project-list.ts";
|
|
21
24
|
import { cleanupStaleProjects, scanStaleProjects } from "../lib/project-operations.ts";
|
|
@@ -63,9 +66,18 @@ export default async function projects(subcommand?: string, args: string[] = [])
|
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
/**
|
|
66
|
-
* Extract a flag value from args (e.g., --status live -> "live")
|
|
69
|
+
* Extract a flag value from args (e.g., --status live -> "live" or --sort=name -> "name")
|
|
67
70
|
*/
|
|
68
71
|
function extractFlagValue(args: string[], flag: string): string | null {
|
|
72
|
+
// Check for --flag=value syntax
|
|
73
|
+
const prefix = `${flag}=`;
|
|
74
|
+
for (const arg of args) {
|
|
75
|
+
if (arg.startsWith(prefix)) {
|
|
76
|
+
return arg.slice(prefix.length) || null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Check for --flag value syntax
|
|
69
81
|
const idx = args.indexOf(flag);
|
|
70
82
|
if (idx !== -1 && idx + 1 < args.length) {
|
|
71
83
|
return args[idx + 1] ?? null;
|
|
@@ -99,6 +111,20 @@ async function listProjects(args: string[]): Promise<void> {
|
|
|
99
111
|
const localOnly = args.includes("--local");
|
|
100
112
|
const cloudOnly = args.includes("--cloud");
|
|
101
113
|
|
|
114
|
+
// Parse --sort flag (default: updated)
|
|
115
|
+
const sortFlag = extractFlagValue(args, "--sort");
|
|
116
|
+
const sortOrder: SortOrder = sortFlag === "name" || sortFlag === "created" ? sortFlag : "updated";
|
|
117
|
+
|
|
118
|
+
// Extract positional filter (first arg that's not a flag or flag value)
|
|
119
|
+
const flagsWithValues = ["--status", "--tag", "--sort"];
|
|
120
|
+
const nameFilter = args.find((arg, idx) => {
|
|
121
|
+
if (arg.startsWith("--") || arg.startsWith("-")) return false;
|
|
122
|
+
// Check if previous arg was a flag that takes a value
|
|
123
|
+
const prevArg = args[idx - 1];
|
|
124
|
+
if (prevArg && flagsWithValues.includes(prevArg)) return false;
|
|
125
|
+
return true;
|
|
126
|
+
});
|
|
127
|
+
|
|
102
128
|
// Fetch all projects from registry and control plane
|
|
103
129
|
outputSpinner.start("Loading projects...");
|
|
104
130
|
const projects: ResolvedProject[] = await listAllProjects();
|
|
@@ -107,7 +133,18 @@ async function listProjects(args: string[]): Promise<void> {
|
|
|
107
133
|
// Convert to list items
|
|
108
134
|
let items = toListItems(projects);
|
|
109
135
|
|
|
110
|
-
// Apply
|
|
136
|
+
// Apply fuzzy name filter first (uses updatedAt for tiebreaker via sort stability)
|
|
137
|
+
if (nameFilter) {
|
|
138
|
+
// Sort by updatedAt descending before fuzzy filter so tiebreaker favors recent
|
|
139
|
+
items.sort((a, b) => {
|
|
140
|
+
const aTime = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
|
|
141
|
+
const bTime = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
|
|
142
|
+
return bTime - aTime;
|
|
143
|
+
});
|
|
144
|
+
items = fuzzyFilter(nameFilter, items, (item) => item.name);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Apply other filters
|
|
111
148
|
if (statusFilter) items = filterByStatus(items, statusFilter);
|
|
112
149
|
if (localOnly) items = items.filter((i) => i.isLocal);
|
|
113
150
|
if (cloudOnly) items = items.filter((i) => i.isCloudOnly);
|
|
@@ -128,6 +165,9 @@ async function listProjects(args: string[]): Promise<void> {
|
|
|
128
165
|
return;
|
|
129
166
|
}
|
|
130
167
|
|
|
168
|
+
// Apply sorting
|
|
169
|
+
items = sortItems(items, sortOrder);
|
|
170
|
+
|
|
131
171
|
// JSON output to stdout (pipeable)
|
|
132
172
|
if (jsonOutput) {
|
|
133
173
|
console.log(JSON.stringify(items, null, 2));
|
|
@@ -146,8 +186,10 @@ async function listProjects(args: string[]): Promise<void> {
|
|
|
146
186
|
|
|
147
187
|
/**
|
|
148
188
|
* Render the grouped view (default)
|
|
189
|
+
* Note: items are already sorted by the caller
|
|
149
190
|
*/
|
|
150
191
|
function renderGroupedView(items: ProjectListItem[]): void {
|
|
192
|
+
// Group projects while preserving the sort order within each group
|
|
151
193
|
const groups = groupProjects(items);
|
|
152
194
|
const total = items.length;
|
|
153
195
|
const CLOUD_LIMIT = 5;
|
|
@@ -173,13 +215,11 @@ function renderGroupedView(items: ProjectListItem[]): void {
|
|
|
173
215
|
console.error(formatLocalSection(groups.local, { tagColorMap }));
|
|
174
216
|
}
|
|
175
217
|
|
|
176
|
-
// Section 3: Cloud-only (show
|
|
218
|
+
// Section 3: Cloud-only (show first N from already-sorted list)
|
|
177
219
|
if (groups.cloudOnly.length > 0) {
|
|
178
|
-
const sorted = sortByUpdated(groups.cloudOnly);
|
|
179
|
-
|
|
180
220
|
console.error("");
|
|
181
221
|
console.error(
|
|
182
|
-
formatCloudSection(
|
|
222
|
+
formatCloudSection(groups.cloudOnly, {
|
|
183
223
|
limit: CLOUD_LIMIT,
|
|
184
224
|
total: groups.cloudOnly.length,
|
|
185
225
|
tagColorMap,
|
|
@@ -200,13 +240,16 @@ function renderGroupedView(items: ProjectListItem[]): void {
|
|
|
200
240
|
|
|
201
241
|
/**
|
|
202
242
|
* Render flat table (for --all mode)
|
|
243
|
+
* Note: items are already sorted by the caller
|
|
203
244
|
*/
|
|
204
245
|
function renderFlatTable(items: ProjectListItem[]): void {
|
|
205
|
-
//
|
|
246
|
+
// Keep errors at the top while preserving relative order within each group
|
|
206
247
|
const sorted = [...items].sort((a, b) => {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
248
|
+
const aIsError = a.status === "error" || a.status === "auth-expired";
|
|
249
|
+
const bIsError = b.status === "error" || b.status === "auth-expired";
|
|
250
|
+
if (aIsError && !bIsError) return -1;
|
|
251
|
+
if (!aIsError && bIsError) return 1;
|
|
252
|
+
return 0; // Preserve existing sort order
|
|
210
253
|
});
|
|
211
254
|
|
|
212
255
|
// Build consistent tag color map
|
package/src/commands/secrets.ts
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { password as passwordPrompt } from "@clack/prompts";
|
|
10
|
-
import { isCancel } from "../lib/hooks.ts";
|
|
11
10
|
import { $ } from "bun";
|
|
12
11
|
import { getControlApiUrl } from "../lib/control-plane.ts";
|
|
13
12
|
import { JackError, JackErrorCode } from "../lib/errors.ts";
|
|
13
|
+
import { isCancel } from "../lib/hooks.ts";
|
|
14
14
|
import { error, info, output, success, warn } from "../lib/output.ts";
|
|
15
15
|
import { type LocalProjectLink, readProjectLink } from "../lib/project-link.ts";
|
|
16
16
|
import { getProjectNameFromDir } from "../lib/storage/index.ts";
|
|
@@ -25,6 +25,10 @@ export default async function secrets(
|
|
|
25
25
|
options: SecretsOptions = {},
|
|
26
26
|
): Promise<void> {
|
|
27
27
|
if (!subcommand) {
|
|
28
|
+
return await listSecrets(options);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (subcommand === "help" || subcommand === "--help" || subcommand === "-h") {
|
|
28
32
|
return showHelp();
|
|
29
33
|
}
|
|
30
34
|
|
package/src/commands/services.ts
CHANGED
|
@@ -438,7 +438,10 @@ async function dbDelete(options: ServiceOptions): Promise<void> {
|
|
|
438
438
|
|
|
439
439
|
// Confirm deletion
|
|
440
440
|
const { promptSelect } = await import("../lib/hooks.ts");
|
|
441
|
-
const choice = await promptSelect(
|
|
441
|
+
const choice = await promptSelect(
|
|
442
|
+
["Yes, delete", "No, cancel"],
|
|
443
|
+
`Delete database '${dbInfo.name}'?`,
|
|
444
|
+
);
|
|
442
445
|
|
|
443
446
|
if (choice !== 0) {
|
|
444
447
|
info("Cancelled");
|
|
@@ -989,7 +992,11 @@ async function storageInfo(args: string[], options: ServiceOptions): Promise<voi
|
|
|
989
992
|
|
|
990
993
|
if (!bucketInfo) {
|
|
991
994
|
console.error("");
|
|
992
|
-
error(
|
|
995
|
+
error(
|
|
996
|
+
bucketName
|
|
997
|
+
? `Bucket "${bucketName}" not found`
|
|
998
|
+
: "No storage buckets found for this project",
|
|
999
|
+
);
|
|
993
1000
|
info("Create one with: jack services storage create");
|
|
994
1001
|
console.error("");
|
|
995
1002
|
return;
|
|
@@ -999,7 +1006,9 @@ async function storageInfo(args: string[], options: ServiceOptions): Promise<voi
|
|
|
999
1006
|
success(`Bucket: ${bucketInfo.name}`);
|
|
1000
1007
|
console.error("");
|
|
1001
1008
|
item(`Binding: ${bucketInfo.binding}`);
|
|
1002
|
-
item(
|
|
1009
|
+
item(
|
|
1010
|
+
`Source: ${bucketInfo.source === "control-plane" ? "managed (jack cloud)" : "BYO (wrangler)"}`,
|
|
1011
|
+
);
|
|
1003
1012
|
console.error("");
|
|
1004
1013
|
} catch (err) {
|
|
1005
1014
|
outputSpinner.stop();
|
|
@@ -1137,7 +1146,10 @@ async function storageDelete(args: string[], options: ServiceOptions): Promise<v
|
|
|
1137
1146
|
|
|
1138
1147
|
// Confirm deletion
|
|
1139
1148
|
const { promptSelect } = await import("../lib/hooks.ts");
|
|
1140
|
-
const choice = await promptSelect(
|
|
1149
|
+
const choice = await promptSelect(
|
|
1150
|
+
["Yes, delete", "No, cancel"],
|
|
1151
|
+
`Delete bucket '${bucketName}'?`,
|
|
1152
|
+
);
|
|
1141
1153
|
|
|
1142
1154
|
if (choice !== 0) {
|
|
1143
1155
|
info("Cancelled");
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shell-init command - output shell integration code
|
|
3
|
+
*
|
|
4
|
+
* Usage: jack shell-init
|
|
5
|
+
*
|
|
6
|
+
* Outputs shell code to stdout. Users can:
|
|
7
|
+
* - eval "$(jack shell-init)" for temporary use
|
|
8
|
+
* - Run `jack init` to install permanently (recommended)
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
detectShell,
|
|
13
|
+
getRcFileName,
|
|
14
|
+
getRcFilePath,
|
|
15
|
+
getShellCode,
|
|
16
|
+
getShellFileDisplayPath,
|
|
17
|
+
getSourceLine,
|
|
18
|
+
} from "../lib/shell-integration.ts";
|
|
19
|
+
|
|
20
|
+
export default async function shellInit(): Promise<void> {
|
|
21
|
+
const code = getShellCode();
|
|
22
|
+
|
|
23
|
+
// If piped (eval), output raw code only
|
|
24
|
+
if (!process.stdout.isTTY) {
|
|
25
|
+
console.log(code);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Interactive: show instructions
|
|
30
|
+
const shell = detectShell();
|
|
31
|
+
const rcFile = getRcFilePath(shell);
|
|
32
|
+
const rcName = rcFile ? getRcFileName(rcFile) : ".bashrc or .zshrc";
|
|
33
|
+
|
|
34
|
+
console.log("# Shell integration for jack");
|
|
35
|
+
console.log("#");
|
|
36
|
+
console.log("# Option 1 (recommended): Run 'jack init' to install automatically");
|
|
37
|
+
console.log("#");
|
|
38
|
+
console.log(`# Option 2: Add this line to your ~/${rcName}:`);
|
|
39
|
+
console.log(`# ${getSourceLine().split("\n")[1]}`);
|
|
40
|
+
console.log(`# Then create ${getShellFileDisplayPath()} with:`);
|
|
41
|
+
console.log("#");
|
|
42
|
+
console.log(code);
|
|
43
|
+
}
|
package/src/commands/ship.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getErrorDetails } from "../lib/errors.ts";
|
|
2
|
-
import {
|
|
2
|
+
import { createReporter, output } from "../lib/output.ts";
|
|
3
3
|
import { deployProject } from "../lib/project-operations.ts";
|
|
4
4
|
|
|
5
5
|
export default async function ship(
|
|
@@ -9,16 +9,7 @@ export default async function ship(
|
|
|
9
9
|
try {
|
|
10
10
|
const result = await deployProject({
|
|
11
11
|
projectPath: process.cwd(),
|
|
12
|
-
reporter:
|
|
13
|
-
start: output.start,
|
|
14
|
-
stop: output.stop,
|
|
15
|
-
spinner,
|
|
16
|
-
info: output.info,
|
|
17
|
-
warn: output.warn,
|
|
18
|
-
error: output.error,
|
|
19
|
-
success: output.success,
|
|
20
|
-
box: output.box,
|
|
21
|
-
},
|
|
12
|
+
reporter: createReporter(),
|
|
22
13
|
interactive: !isCi,
|
|
23
14
|
includeSecrets: !options.dryRun,
|
|
24
15
|
includeSync: !options.dryRun,
|