@specific.dev/cli 0.1.123 → 0.1.124
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/admin/404/index.html +1 -1
- package/dist/admin/404.html +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/__next._full.txt +1 -1
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +1 -1
- package/dist/admin/__next._tree.txt +1 -1
- package/dist/admin/_not-found/__next._full.txt +1 -1
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.txt +1 -1
- package/dist/admin/_not-found/__next._tree.txt +1 -1
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/databases/__next._full.txt +1 -1
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +1 -1
- package/dist/admin/databases/__next._tree.txt +1 -1
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +1 -1
- package/dist/admin/fullscreen/__next._full.txt +1 -1
- package/dist/admin/fullscreen/__next._head.txt +1 -1
- package/dist/admin/fullscreen/__next._index.txt +1 -1
- package/dist/admin/fullscreen/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/index.html +1 -1
- package/dist/admin/fullscreen/databases/index.txt +1 -1
- package/dist/admin/fullscreen/index.html +1 -1
- package/dist/admin/fullscreen/index.txt +1 -1
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/mail/__next._full.txt +1 -1
- package/dist/admin/mail/__next._head.txt +1 -1
- package/dist/admin/mail/__next._index.txt +1 -1
- package/dist/admin/mail/__next._tree.txt +1 -1
- package/dist/admin/mail/index.html +1 -1
- package/dist/admin/mail/index.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
- package/dist/admin/workflows/__next._full.txt +1 -1
- package/dist/admin/workflows/__next._head.txt +1 -1
- package/dist/admin/workflows/__next._index.txt +1 -1
- package/dist/admin/workflows/__next._tree.txt +1 -1
- package/dist/admin/workflows/index.html +1 -1
- package/dist/admin/workflows/index.txt +1 -1
- package/dist/cli.js +63 -10
- package/dist/docs/index.md +1 -3
- package/dist/docs/integrations/temporal.md +1 -91
- package/dist/docs/temporal.md +0 -2
- package/package.json +1 -1
- /package/dist/admin/_next/static/{iKEnJVRd6gOzhr5N6iD4r → mW_zIz1G5hK3GXQcXI7Kb}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{iKEnJVRd6gOzhr5N6iD4r → mW_zIz1G5hK3GXQcXI7Kb}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{iKEnJVRd6gOzhr5N6iD4r → mW_zIz1G5hK3GXQcXI7Kb}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -373341,7 +373341,7 @@ function trackEvent(event, properties) {
|
|
|
373341
373341
|
event,
|
|
373342
373342
|
properties: {
|
|
373343
373343
|
...properties,
|
|
373344
|
-
cli_version: "0.1.
|
|
373344
|
+
cli_version: "0.1.124",
|
|
373345
373345
|
platform: process.platform,
|
|
373346
373346
|
node_version: process.version,
|
|
373347
373347
|
project_id: getProjectId()
|
|
@@ -373666,10 +373666,6 @@ import { fileURLToPath as fileURLToPath3 } from "url";
|
|
|
373666
373666
|
|
|
373667
373667
|
// src/lib/beta/registry.ts
|
|
373668
373668
|
var BETA_REGISTRY = [
|
|
373669
|
-
{
|
|
373670
|
-
name: "temporal",
|
|
373671
|
-
description: "Managed Temporal workflow engine for durable workflows and background tasks"
|
|
373672
|
-
},
|
|
373673
373669
|
{
|
|
373674
373670
|
name: "mail",
|
|
373675
373671
|
description: "Managed email sending via SMTP for transactional emails"
|
|
@@ -375223,6 +375219,7 @@ function PhaseIndicator({
|
|
|
375223
375219
|
showSpinner = true
|
|
375224
375220
|
}) {
|
|
375225
375221
|
const phases = [
|
|
375222
|
+
"creating-preview",
|
|
375226
375223
|
"creating-tarball",
|
|
375227
375224
|
"creating-deployment",
|
|
375228
375225
|
"uploading",
|
|
@@ -375374,7 +375371,7 @@ function formatErrorCode(code) {
|
|
|
375374
375371
|
function StructuredError({ error }) {
|
|
375375
375372
|
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, /* @__PURE__ */ React7.createElement(Text7, { color: "red", bold: true }, formatErrorCode(error.code), ": ", error.message), error.resource && /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, "Resource: ", error.resource), error.output && /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { bold: true }, "Output:"), /* @__PURE__ */ React7.createElement(Text7, null, error.output)));
|
|
375376
375373
|
}
|
|
375377
|
-
function DeployUI({ envFlag, config }) {
|
|
375374
|
+
function DeployUI({ envFlag, preview, config }) {
|
|
375378
375375
|
const { exit } = useApp3();
|
|
375379
375376
|
const [state, setState] = useState6({ phase: "checking-auth" });
|
|
375380
375377
|
const clientRef = React7.useRef(null);
|
|
@@ -375562,6 +375559,15 @@ function DeployUI({ envFlag, config }) {
|
|
|
375562
375559
|
}));
|
|
375563
375560
|
return;
|
|
375564
375561
|
}
|
|
375562
|
+
if (preview) {
|
|
375563
|
+
setState((s) => ({
|
|
375564
|
+
...s,
|
|
375565
|
+
phase: "creating-preview",
|
|
375566
|
+
environments,
|
|
375567
|
+
previewStatus: "Creating preview environment"
|
|
375568
|
+
}));
|
|
375569
|
+
return;
|
|
375570
|
+
}
|
|
375565
375571
|
if (envFlag) {
|
|
375566
375572
|
const match = environments.find((e) => e.name === envFlag);
|
|
375567
375573
|
if (!match) {
|
|
@@ -375624,6 +375630,45 @@ function DeployUI({ envFlag, config }) {
|
|
|
375624
375630
|
cancelled = true;
|
|
375625
375631
|
};
|
|
375626
375632
|
}, [state.phase, state.projectId]);
|
|
375633
|
+
useEffect6(() => {
|
|
375634
|
+
if (state.phase !== "creating-preview" || !state.projectId) return;
|
|
375635
|
+
let cancelled = false;
|
|
375636
|
+
async function createPreview() {
|
|
375637
|
+
try {
|
|
375638
|
+
const token = await getValidAccessToken();
|
|
375639
|
+
const client2 = new SpecificClient({ accessToken: token });
|
|
375640
|
+
const projectDir = process.cwd();
|
|
375641
|
+
const previousPreviewId = readPreviewEnvironmentId(projectDir);
|
|
375642
|
+
if (previousPreviewId) {
|
|
375643
|
+
setState((s) => ({ ...s, previewStatus: "Tearing down previous preview environment" }));
|
|
375644
|
+
try {
|
|
375645
|
+
await client2.deletePreviewEnvironment(previousPreviewId);
|
|
375646
|
+
} catch {
|
|
375647
|
+
}
|
|
375648
|
+
}
|
|
375649
|
+
if (cancelled) return;
|
|
375650
|
+
setState((s) => ({ ...s, previewStatus: "Creating preview environment" }));
|
|
375651
|
+
const previewEnv = await client2.createPreviewEnvironment(state.projectId);
|
|
375652
|
+
writePreviewEnvironmentId(previewEnv.id, projectDir);
|
|
375653
|
+
if (cancelled) return;
|
|
375654
|
+
setState((s) => ({
|
|
375655
|
+
...s,
|
|
375656
|
+
phase: "creating-tarball",
|
|
375657
|
+
environmentName: previewEnv.name
|
|
375658
|
+
}));
|
|
375659
|
+
} catch (err) {
|
|
375660
|
+
if (cancelled) return;
|
|
375661
|
+
setState({
|
|
375662
|
+
phase: "error",
|
|
375663
|
+
error: err instanceof Error ? err.message : String(err)
|
|
375664
|
+
});
|
|
375665
|
+
}
|
|
375666
|
+
}
|
|
375667
|
+
createPreview();
|
|
375668
|
+
return () => {
|
|
375669
|
+
cancelled = true;
|
|
375670
|
+
};
|
|
375671
|
+
}, [state.phase, state.projectId]);
|
|
375627
375672
|
const handleEnvironmentSelect = useCallback3(
|
|
375628
375673
|
(env2) => {
|
|
375629
375674
|
writeEnvironmentId(env2.id);
|
|
@@ -376175,7 +376220,14 @@ function DeployUI({ envFlag, config }) {
|
|
|
376175
376220
|
}
|
|
376176
376221
|
return "Preparing";
|
|
376177
376222
|
};
|
|
376178
|
-
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" },
|
|
376223
|
+
return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React7.createElement(Text7, null, /* @__PURE__ */ React7.createElement(Text7, { bold: true, color: "cyan" }, preview ? `Deploying preview${environment !== "prod" ? ` (${environment})` : ""}` : `Deploying to ${environment}`), deployment && /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " (", deployment.id, ")")), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, preview && /* @__PURE__ */ React7.createElement(
|
|
376224
|
+
PhaseIndicator,
|
|
376225
|
+
{
|
|
376226
|
+
phase: "creating-preview",
|
|
376227
|
+
currentPhase: displayPhase,
|
|
376228
|
+
label: state.previewStatus || "Creating preview environment"
|
|
376229
|
+
}
|
|
376230
|
+
), /* @__PURE__ */ React7.createElement(
|
|
376179
376231
|
PhaseIndicator,
|
|
376180
376232
|
{
|
|
376181
376233
|
phase: "creating-tarball",
|
|
@@ -376492,7 +376544,7 @@ async function deployCommand(options2) {
|
|
|
376492
376544
|
console.error(formatConfigError(err, hcl, configPath));
|
|
376493
376545
|
process.exit(1);
|
|
376494
376546
|
}
|
|
376495
|
-
const hasNonInteractiveFlags = options2.project || options2.secret?.length || options2.config?.length
|
|
376547
|
+
const hasNonInteractiveFlags = options2.project || options2.secret?.length || options2.config?.length;
|
|
376496
376548
|
if (!isInteractive() || hasNonInteractiveFlags) {
|
|
376497
376549
|
await runDeployPipeline({
|
|
376498
376550
|
config,
|
|
@@ -376509,6 +376561,7 @@ async function deployCommand(options2) {
|
|
|
376509
376561
|
DeployUI,
|
|
376510
376562
|
{
|
|
376511
376563
|
envFlag: options2.env,
|
|
376564
|
+
preview: options2.preview,
|
|
376512
376565
|
config
|
|
376513
376566
|
}
|
|
376514
376567
|
)
|
|
@@ -377369,7 +377422,7 @@ function compareVersions(a, b) {
|
|
|
377369
377422
|
return 0;
|
|
377370
377423
|
}
|
|
377371
377424
|
async function checkForUpdate() {
|
|
377372
|
-
const currentVersion = "0.1.
|
|
377425
|
+
const currentVersion = "0.1.124";
|
|
377373
377426
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
377374
377427
|
if (!response.ok) {
|
|
377375
377428
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -377639,7 +377692,7 @@ async function projectListCommand() {
|
|
|
377639
377692
|
var program = new Command();
|
|
377640
377693
|
var env = "production";
|
|
377641
377694
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
377642
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
377695
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.124").enablePositionalOptions();
|
|
377643
377696
|
program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").addHelpText("after", `
|
|
377644
377697
|
Examples:
|
|
377645
377698
|
$ specific init
|
package/dist/docs/index.md
CHANGED
|
@@ -22,9 +22,7 @@ A full development environment can be started with `specific dev`. To deploy any
|
|
|
22
22
|
- [Storage](/storage): define S3-compatible object/blob storage for services to store files in.
|
|
23
23
|
- [Redis](/redis): define non-durable Redis-compatible databases for caching and more.
|
|
24
24
|
- [Volumes](/volumes): define persistent storage volumes for services to store files in.
|
|
25
|
-
<!-- beta:temporal -->
|
|
26
25
|
- [Temporal](/temporal): managed durable workflow engine for background tasks, AI agents, cron jobs and more.
|
|
27
|
-
<!-- /beta:temporal -->
|
|
28
26
|
<!-- beta:mail -->
|
|
29
27
|
- [Mail](/mail): managed email sending via SMTP for transactional emails.
|
|
30
28
|
<!-- /beta:mail -->
|
|
@@ -37,7 +35,7 @@ The following is a list of common frameworks and libraries with guidance on how
|
|
|
37
35
|
- [Next.js](/integrations/nextjs): full-stack React framework
|
|
38
36
|
- [Drizzle ORM](/integrations/drizzle): TypeScript ORM with type safety
|
|
39
37
|
- [Prisma](/integrations/prisma): TypeScript ORM with auto-generated client
|
|
40
|
-
- [Temporal](/integrations/temporal):
|
|
38
|
+
- [Temporal](/integrations/temporal): using Temporal with Specific for durable workflows, background tasks, AI agents, cron jobs and more
|
|
41
39
|
|
|
42
40
|
## Adding Specific to existing projects / migrating to Specific
|
|
43
41
|
|
|
@@ -1,93 +1,3 @@
|
|
|
1
1
|
# Temporal
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> **Beta**: Specific now has built-in Temporal support. See [Temporal](/temporal) for the recommended approach using the `temporal` block. The manual setup below still works but is no longer needed.
|
|
5
|
-
<!-- /beta:temporal -->
|
|
6
|
-
|
|
7
|
-
Temporal is a durable workflow engine. This guide covers running Temporal locally during development and connecting to Temporal Cloud in production.
|
|
8
|
-
|
|
9
|
-
Temporal has extensive SDK support across many languages including TypeScript, Python, Go, Java, .NET, and PHP. See the [Temporal documentation](https://docs.temporal.io/) for language-specific guides on implementing workers, workflows, and activities. This document only covers integration with Specific.
|
|
10
|
-
|
|
11
|
-
## Configuration
|
|
12
|
-
|
|
13
|
-
Define a dev-only Temporal service that runs locally, along with configs and secrets for production Temporal Cloud.
|
|
14
|
-
|
|
15
|
-
```hcl
|
|
16
|
-
build "app" {
|
|
17
|
-
base = "node"
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
# Dev-only service: runs local Temporal server during development
|
|
21
|
-
# No top-level command means it's excluded from production deployment
|
|
22
|
-
#
|
|
23
|
-
service "temporal" {
|
|
24
|
-
endpoint "grpc" {}
|
|
25
|
-
endpoint "ui" { public = true }
|
|
26
|
-
|
|
27
|
-
dev {
|
|
28
|
-
command = "temporal server start-dev --port $GRPC_PORT --ui-port $UI_PORT --db-filename /tmp/temporal.db"
|
|
29
|
-
env = {
|
|
30
|
-
GRPC_PORT = endpoint.grpc.port
|
|
31
|
-
UI_PORT = endpoint.ui.port
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
# Temporal Cloud address (e.g., your-namespace.tmprl.cloud:7233)
|
|
37
|
-
config "temporal_address" {}
|
|
38
|
-
|
|
39
|
-
# Namespace - uses "default" in dev, must be set for production
|
|
40
|
-
config "temporal_namespace" {
|
|
41
|
-
dev {
|
|
42
|
-
default = "default"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
# API key for Temporal Cloud - not required in dev
|
|
47
|
-
secret "temporal_api_key" {
|
|
48
|
-
dev {
|
|
49
|
-
required = false
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
service "app" {
|
|
54
|
-
build = build.app
|
|
55
|
-
command = "node index.js"
|
|
56
|
-
expose {}
|
|
57
|
-
|
|
58
|
-
env = {
|
|
59
|
-
PORT = port
|
|
60
|
-
TEMPORAL_ADDRESS = config.temporal_address
|
|
61
|
-
TEMPORAL_NAMESPACE = config.temporal_namespace
|
|
62
|
-
TEMPORAL_API_KEY = secret.temporal_api_key
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
dev {
|
|
66
|
-
command = "node --watch index.js"
|
|
67
|
-
env = {
|
|
68
|
-
# Override to use local Temporal service instead
|
|
69
|
-
TEMPORAL_ADDRESS = ""
|
|
70
|
-
TEMPORAL_HOST = service.temporal.endpoint.grpc.host
|
|
71
|
-
TEMPORAL_PORT = service.temporal.endpoint.grpc.port
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
## Development
|
|
78
|
-
|
|
79
|
-
Running `specific dev` automatically starts a local Temporal server. The user must install the Temporal CLI for this: https://temporal.io/setup/install-temporal-cli. The Temporal Web UI is available at the public endpoint URL shown in the output.
|
|
80
|
-
|
|
81
|
-
Your app connects to the local Temporal server using the service endpoint environment variables (`TEMPORAL_HOST` and `TEMPORAL_PORT`).
|
|
82
|
-
|
|
83
|
-
## Production
|
|
84
|
-
|
|
85
|
-
In production, the dev-only `temporal` service is excluded from deployment. Your app connects to Temporal Cloud using:
|
|
86
|
-
|
|
87
|
-
1. `temporal_address` - Your Temporal Cloud address (e.g., `your-namespace.tmprl.cloud:7233`)
|
|
88
|
-
2. `temporal_namespace` - Your Temporal Cloud namespace
|
|
89
|
-
3. `temporal_api_key` - API key for authentication
|
|
90
|
-
|
|
91
|
-
Set these with `specific secrets set` before deploying.
|
|
92
|
-
|
|
93
|
-
## SDK support
|
|
3
|
+
Specific has built-in Temporal support via the `temporal` block. See [Temporal](/temporal) for the full guide on configuration, development, and production deployment.
|
package/dist/docs/temporal.md
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
<!-- beta:temporal -->
|
|
2
1
|
# Temporal
|
|
3
2
|
|
|
4
3
|
Define managed Temporal workflow engines for durable workflows, background tasks, AI agents, cron jobs, batch jobs and more.
|
|
@@ -66,4 +65,3 @@ Running `specific deploy` automatically provisions a managed [Temporal Cloud](ht
|
|
|
66
65
|
4. Credentials are securely injected into your services
|
|
67
66
|
|
|
68
67
|
The reference attributes (`temporal.<name>.url`, `.namespace`, `.api_key`) resolve to the Temporal Cloud values in production, so no environment-specific overrides are needed.
|
|
69
|
-
<!-- /beta:temporal -->
|
package/package.json
CHANGED
/package/dist/admin/_next/static/{iKEnJVRd6gOzhr5N6iD4r → mW_zIz1G5hK3GXQcXI7Kb}/_buildManifest.js
RENAMED
|
File without changes
|
|
File without changes
|
/package/dist/admin/_next/static/{iKEnJVRd6gOzhr5N6iD4r → mW_zIz1G5hK3GXQcXI7Kb}/_ssgManifest.js
RENAMED
|
File without changes
|