sim-setup 1.0.2 → 1.0.3-preview.50.1

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.
Files changed (3) hide show
  1. package/README.md +277 -6
  2. package/dist/index.js +463 -41
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,17 +1,288 @@
1
- # sim-setup
1
+ # Sim Setup
2
2
 
3
- Set up and manage a self-hosted Sim installation.
3
+ `sim-setup` is the installer and management tool for a self-hosted
4
+ [Sim](https://sim.ai) deployment. Sim is a workspace for building, deploying,
5
+ and managing AI agents and workflows.
6
+
7
+ For an npm user, `sim-setup` creates a Docker Compose installation from published
8
+ Sim images. It generates the required secrets, writes the deployment files,
9
+ starts the containers, runs database migrations, and checks that the application
10
+ is healthy. It does not clone the Sim repository.
11
+
12
+ This package installs the Sim server. To manage workflows, tables, files, and
13
+ other resources in a running Sim workspace, use the separate
14
+ [`sim` CLI](https://www.npmjs.com/package/sim).
15
+
16
+ ## Requirements
17
+
18
+ - Node.js 20 or newer
19
+ - Docker with the Compose plugin
20
+ - Ports `3000`, `3002`, and, by default, `5432` available
21
+ - At least 12 GB of system memory and 20 GB of free disk for a small installation
22
+
23
+ Allocate at least 8 GB of memory to Docker for reliable workflow execution.
24
+ Docker Desktop, OrbStack, Colima, and Docker Engine are supported as long as the
25
+ `docker` command can reach the daemon.
26
+
27
+ ## Install and run
28
+
29
+ You normally do not need to install the package globally:
4
30
 
5
31
  ```bash
6
32
  npx sim-setup
7
33
  ```
8
34
 
9
- Outside a Sim source checkout, the command creates a Docker Compose installation using published
10
- images. Inside a Sim source checkout, use `bun run sim-setup` to expose the complete development
11
- and deployment wizard.
35
+ To install it globally instead:
36
+
37
+ ```bash
38
+ npm install --global sim-setup
39
+ sim-setup
40
+ ```
41
+
42
+ The examples below use `npx`; omit it if you installed the package globally.
43
+
44
+ The default standalone setup creates a `sim` directory under the current
45
+ directory:
46
+
47
+ ```text
48
+ sim/
49
+ ├── .env
50
+ ├── .sim-setup.json
51
+ └── docker-compose.prod.yml
52
+ ```
53
+
54
+ Use `--dir` to choose an explicit location:
55
+
56
+ ```bash
57
+ npx sim-setup --dir /srv/sim
58
+ ```
59
+
60
+ When setup finishes, open [http://localhost:3000](http://localhost:3000) and
61
+ create the first account.
62
+
63
+ ## What the setup wizard does
64
+
65
+ The wizard:
66
+
67
+ 1. checks Docker, available ports, memory, and disk space
68
+ 2. creates or reuses the installation directory
69
+ 3. generates authentication, encryption, internal API, and scheduler secrets
70
+ 4. optionally connects Sim Chat and model providers
71
+ 5. writes `.env` and the managed production Compose file
72
+ 6. starts PostgreSQL, Redis, the Sim application, realtime, and scheduled jobs
73
+ 7. runs migrations and waits for the health checks to pass
74
+
75
+ Choose **Quick** for sensible defaults and the fewest questions. Choose
76
+ **Custom** to configure additional options such as object storage, email,
77
+ sign-in providers, security settings, and self-hosted feature flags. Skip the
78
+ prompt with:
79
+
80
+ ```bash
81
+ npx sim-setup --quick
82
+ ```
83
+
84
+ The wizard detects an existing installation. Re-running it lets you keep and
85
+ check the current configuration, review and update it, or archive the current
86
+ `.env` and build a new configuration. If setup fails partway through, fix the
87
+ reported problem and run the same command again; completed configuration is
88
+ preserved.
89
+
90
+ ## Chat and model access
91
+
92
+ Sim can run without the optional Chat API key. If you skip Chat setup, the
93
+ wizard hides the Chat module instead of leaving it enabled but unusable. Connect
94
+ or replace the key later with:
95
+
96
+ ```bash
97
+ npx sim-setup add chat
98
+ npx sim-setup start
99
+ ```
100
+
101
+ Agent blocks also need access to a model provider. Configure provider keys in a
102
+ workspace in the Sim UI, pass supported keys such as `OPENAI_API_KEY` or
103
+ `ANTHROPIC_API_KEY` into the setup environment, or add deployment-wide model
104
+ configuration later:
105
+
106
+ ```bash
107
+ npx sim-setup add llm
108
+ npx sim-setup start
109
+ ```
110
+
111
+ For Docker Compose installations, `add` updates `.env` but does not recreate the
112
+ application container. Run `npx sim-setup start` afterward to apply the changed
113
+ environment. `restart` only restarts containers with their current configuration.
114
+
115
+ ## Manage the installation
116
+
117
+ Run commands from the installation directory or pass `--dir <path>` to target a
118
+ specific installation.
119
+
120
+ | Command | What it does |
121
+ | --- | --- |
122
+ | `npx sim-setup status` | Show detected installations, container state, and app health |
123
+ | `npx sim-setup logs` | Follow the last 100 lines of Docker Compose logs |
124
+ | `npx sim-setup start` | Start or reconcile the containers; data is kept |
125
+ | `npx sim-setup stop` | Stop containers without removing them |
126
+ | `npx sim-setup restart` | Restart the current containers |
127
+ | `npx sim-setup update` | Refresh the managed Compose file, pull images, recreate services, and run migrations |
128
+ | `npx sim-setup down` | Remove containers but keep data volumes |
129
+ | `npx sim-setup reset` | Archive `.env`, remove containers, and delete managed data volumes |
130
+
131
+ `down` and `reset` are deliberately different. Use `down` when you want to
132
+ remove containers and bring the same installation back later. `reset` is a
133
+ destructive fresh start and asks for confirmation before deleting data.
134
+
135
+ ### Check configuration
136
+
137
+ `config` reports which effective configuration sources, capabilities, and OAuth
138
+ integrations were detected. It does not print secret values:
139
+
140
+ ```bash
141
+ npx sim-setup config
142
+ ```
143
+
144
+ `doctor` validates environment files, required values, cross-service
145
+ consistency, and live dependencies:
12
146
 
13
- To connect or replace the Chat API key without rerunning the full wizard:
147
+ ```bash
148
+ npx sim-setup doctor
149
+ npx sim-setup doctor --fix
150
+ npx sim-setup doctor --json
151
+ ```
152
+
153
+ Use `config` to answer “what is configured?” and `status` to answer “what is
154
+ running and healthy?”
155
+
156
+ ### Install the desktop app
157
+
158
+ `desktop` resolves the macOS installer from your own deployment and prints the
159
+ server URL to enter in the app:
160
+
161
+ ```bash
162
+ npx sim-setup desktop
163
+ npx sim-setup desktop --url https://sim.example.com
164
+ npx sim-setup desktop --no-open
165
+ ```
166
+
167
+ The desktop app is not tied to sim.ai — it bakes in only a default server, and
168
+ every Sim deployment already serves `/api/desktop/update/download` and the
169
+ update feed installed apps poll. Install the signed build, then point it at your
170
+ deployment with **Sim → Server…**. Nothing has to be built or signed by you.
171
+
172
+ ### Add or change capabilities
173
+
174
+ Configure one capability without walking through the complete wizard:
14
175
 
15
176
  ```bash
177
+ npx sim-setup add email
178
+ npx sim-setup add storage
179
+ npx sim-setup add sandbox
180
+ npx sim-setup add jobs
181
+ npx sim-setup add cache
182
+ npx sim-setup add knowledge
183
+ npx sim-setup add knowledge-embeddings
16
184
  npx sim-setup add chat
185
+ npx sim-setup add llm
186
+ npx sim-setup add integration slack
187
+ ```
188
+
189
+ Run `npx sim-setup start` after changing a Docker Compose capability so the app
190
+ container receives the new environment.
191
+
192
+ ## Updating
193
+
194
+ Update a Docker Compose installation with:
195
+
196
+ ```bash
197
+ npx sim-setup update
198
+ npx sim-setup status
199
+ ```
200
+
201
+ The update command keeps Docker volumes, applies the current managed Compose
202
+ file, pulls the version selected by `SIM_VERSION`, and runs migrations. If
203
+ `SIM_VERSION` is unset, the deployment tracks `latest`.
204
+
205
+ For production, pin an explicit version, back up the database first, and read
206
+ the [upgrade guide](https://docs.sim.ai/platform/self-hosting/upgrades). Docker
207
+ Compose updates briefly interrupt the application because Compose does not
208
+ provide rolling deployments.
209
+
210
+ ## Files, secrets, and data
211
+
212
+ The generated `.env` contains credentials and encryption keys. It is written
213
+ with owner-only permissions and must not be committed to source control.
214
+
215
+ Back up `.env` securely outside the server before using the deployment for real
216
+ data. In particular, `ENCRYPTION_KEY` and `API_ENCRYPTION_KEY` protect stored
217
+ credentials and API keys. A database backup restored without the matching keys
218
+ contains data that Sim cannot decrypt.
219
+
220
+ PostgreSQL data lives in a Docker volume. These commands preserve it:
221
+
222
+ - `start`
223
+ - `stop`
224
+ - `restart`
225
+ - `update`
226
+ - `down`
227
+
228
+ `reset` deletes managed volumes. It archives `.env` beside the installation
229
+ before doing so, but that local archive is not a substitute for an off-machine
230
+ backup.
231
+
232
+ The default local file-storage fallback is different: uploaded files live inside
233
+ the application container, not in a managed volume. They can be lost when the
234
+ container is removed or recreated, including during `down` or `update`.
235
+ Configure object storage before keeping files you care about.
236
+
237
+ ## Production deployments
238
+
239
+ The generated Compose installation is suitable for local evaluation and a
240
+ single-node deployment. Before exposing it publicly, configure at least:
241
+
242
+ - a public application URL and TLS reverse proxy
243
+ - database and `.env` backups
244
+ - durable object storage for uploaded files
245
+ - email delivery for invitations and email-based authentication
246
+ - OAuth applications for integrations you plan to use
247
+ - a pinned Sim version and an upgrade procedure
248
+
249
+ See the [Docker deployment guide](https://docs.sim.ai/platform/self-hosting/docker)
250
+ and the complete [self-hosting documentation](https://docs.sim.ai/platform/self-hosting).
251
+
252
+ ## Working from the Sim source repository
253
+
254
+ Inside a cloned Sim repository, use:
255
+
256
+ ```bash
257
+ bun run sim-setup
258
+ ```
259
+
260
+ The source checkout adds local development and Kubernetes modes:
261
+
262
+ ```bash
263
+ bun run sim-setup --mode dev
264
+ bun run sim-setup --mode k8s
265
+ ```
266
+
267
+ Standalone npm use supports Docker Compose mode only. Development and Kubernetes
268
+ modes need source-only files and are rejected outside a complete checkout.
269
+
270
+ ## Help
271
+
272
+ ```bash
273
+ npx sim-setup --help
274
+ npx sim-setup --version
17
275
  ```
276
+
277
+ Further documentation:
278
+
279
+ - [Self-hosting overview](https://docs.sim.ai/platform/self-hosting)
280
+ - [Docker Compose](https://docs.sim.ai/platform/self-hosting/docker)
281
+ - [Environment variables](https://docs.sim.ai/platform/self-hosting/environment-variables)
282
+ - [Upgrades](https://docs.sim.ai/platform/self-hosting/upgrades)
283
+ - [Troubleshooting](https://docs.sim.ai/platform/self-hosting/troubleshooting)
284
+ - [Verification checklist](https://docs.sim.ai/platform/self-hosting/verify)
285
+
286
+ ## License
287
+
288
+ Apache-2.0
package/dist/index.js CHANGED
@@ -1561,7 +1561,8 @@ var init_env_capabilities = __esm(() => {
1561
1561
  "microsoft-dataverse",
1562
1562
  "microsoft-excel",
1563
1563
  "microsoft-teams",
1564
- "microsoft-planner"
1564
+ "microsoft-planner",
1565
+ "microsoft-word"
1565
1566
  ]);
1566
1567
  });
1567
1568
 
@@ -1569,7 +1570,7 @@ var init_env_capabilities = __esm(() => {
1569
1570
  var integrations_default;
1570
1571
  var init_integrations = __esm(() => {
1571
1572
  integrations_default = {
1572
- updatedAt: "2026-08-21",
1573
+ updatedAt: "2026-08-26",
1573
1574
  integrations: [
1574
1575
  {
1575
1576
  type: "onepassword",
@@ -8988,11 +8989,11 @@ var init_integrations = __esm(() => {
8988
8989
  operations: [
8989
8990
  {
8990
8991
  name: "Find Email",
8991
- description: "Find a verified B2B email address from a full name and company domain or name. Uses the Enrow async finder — submits a search and polls until the result is ready. Costs 1 credit per valid email found. (https://enrow.readme.io/reference/find-single-email)"
8992
+ description: "Find a verified B2B email address from a full name and company domain or name. Uses the Enrow async finder — submits a search and polls until the result is ready. Costs 1 credit per valid email found. (https://docs.enrow.io/api-reference/email-finder/find-single)"
8992
8993
  },
8993
8994
  {
8994
8995
  name: "Verify Email",
8995
- description: "Verify the deliverability of an email address using the Enrow async verifier. Submits a verification request and polls until the result is ready. Costs 0.25 credits per verification. (https://enrow.readme.io/reference/verify-single-email)"
8996
+ description: "Verify the deliverability of an email address using the Enrow async verifier. Submits a verification request and polls until the result is ready. Costs 0.25 credits per verification. (https://docs.enrow.io/api-reference/email-verifier/verify-single)"
8996
8997
  }
8997
8998
  ],
8998
8999
  operationCount: 2,
@@ -16126,6 +16127,58 @@ var init_integrations = __esm(() => {
16126
16127
  integrationType: "communication",
16127
16128
  tags: ["messaging", "microsoft-365"]
16128
16129
  },
16130
+ {
16131
+ type: "microsoft_word",
16132
+ slug: "microsoft-word",
16133
+ name: "Microsoft Word",
16134
+ description: "Create, fill, read, edit, and export Word documents",
16135
+ longDescription: "Integrate Microsoft Word into the workflow. Create .docx documents from text, fill a formatted template by substituting its placeholders, read a document back as text, replace or append content, find and replace text across the body plus headers and footers, list and search documents in OneDrive or SharePoint, and export a document as PDF.",
16136
+ bgColor: "#FFFFFF",
16137
+ iconName: "MicrosoftWordIcon",
16138
+ docsUrl: "https://docs.sim.ai/integrations/microsoft_word",
16139
+ operations: [
16140
+ {
16141
+ name: "Read Document",
16142
+ description: "Read the text content of a Microsoft Word (.docx) document stored in OneDrive or SharePoint."
16143
+ },
16144
+ {
16145
+ name: "Create Document",
16146
+ description: "Create a new Microsoft Word (.docx) document in OneDrive or SharePoint from text content. Supports Markdown headings (# ## ###), bullets (-), and inline **bold** / *italic*. An existing document with the same name is never overwritten — the new one is given a unique name instead."
16147
+ },
16148
+ {
16149
+ name: "Create from Template",
16150
+ description: "Copy an existing Microsoft Word (.docx) template to a new document and fill its placeholders. The template keeps all of its formatting, styles, headers, and footers, and is never modified. An existing document with the same name is never overwritten — the new one is given a unique name instead."
16151
+ },
16152
+ {
16153
+ name: "Replace Content",
16154
+ description: "Replace the entire contents of an existing Microsoft Word (.docx) document with new text. The previous content and its formatting are discarded — use Append to add to a document instead."
16155
+ },
16156
+ {
16157
+ name: "Append Content",
16158
+ description: "Append plain-text paragraphs to the end of an existing Microsoft Word (.docx) document, leaving the existing content and formatting intact. Fails rather than overwriting if someone else changed the document while the edit was in flight."
16159
+ },
16160
+ {
16161
+ name: "Find and Replace Text",
16162
+ description: "Find and replace text throughout a Microsoft Word (.docx) document, including its headers and footers. Use this to fill placeholders in a template document. Fails rather than overwriting if someone else changed the document while the edit was in flight."
16163
+ },
16164
+ {
16165
+ name: "List Documents",
16166
+ description: "List or search Microsoft Word (.docx) documents in OneDrive or SharePoint. Non-Word items are filtered out of the results."
16167
+ },
16168
+ {
16169
+ name: "Export as PDF",
16170
+ description: "Convert a Microsoft Word (.docx) document to PDF using Microsoft Graph and return it as a file."
16171
+ }
16172
+ ],
16173
+ operationCount: 8,
16174
+ triggers: [],
16175
+ triggerCount: 0,
16176
+ authType: "oauth",
16177
+ oauthServiceId: "microsoft-word",
16178
+ category: "tools",
16179
+ integrationType: "documents",
16180
+ tags: ["microsoft-365", "document-processing", "cloud"]
16181
+ },
16129
16182
  {
16130
16183
  type: "millionverifier",
16131
16184
  slug: "millionverifier",
@@ -21246,6 +21299,201 @@ var init_integrations = __esm(() => {
21246
21299
  integrationType: "hr",
21247
21300
  tags: ["automation"]
21248
21301
  },
21302
+ {
21303
+ type: "semrush",
21304
+ slug: "semrush",
21305
+ name: "Semrush",
21306
+ description: "Research SEO and paid search data with Semrush",
21307
+ longDescription: "Query the Semrush SEO API for domain, subdomain, and URL traffic overviews, organic and paid keywords, ad and product listing creatives, competitor sets, keyword research, and backlink profiles. Requires a Semrush subscription with API units.",
21308
+ bgColor: "#FFFFFF",
21309
+ iconName: "SemrushIcon",
21310
+ docsUrl: "https://docs.sim.ai/integrations/semrush",
21311
+ operations: [
21312
+ {
21313
+ name: "Domain Overview",
21314
+ description: "Get the Semrush rank plus organic and paid search totals for a domain in one regional database."
21315
+ },
21316
+ {
21317
+ name: "Domain Overview (All Databases)",
21318
+ description: "Get organic and paid search totals for a domain across every regional Semrush database."
21319
+ },
21320
+ {
21321
+ name: "Domain Overview History",
21322
+ description: "Get the historical trend of a domain rank plus its organic and paid search totals."
21323
+ },
21324
+ {
21325
+ name: "Domain Organic Keywords",
21326
+ description: "List the keywords a domain ranks for in Google organic search, with position, volume, and traffic share."
21327
+ },
21328
+ {
21329
+ name: "Domain Paid Keywords",
21330
+ description: "List the keywords a domain buys in Google Ads, with ad position, copy, and traffic share."
21331
+ },
21332
+ {
21333
+ name: "Domain Ad Copies",
21334
+ description: "List the unique Google Ads creatives a domain runs, with title, description, and keyword count."
21335
+ },
21336
+ {
21337
+ name: "Domain Ad History",
21338
+ description: "List a domain past Google Ads placements month by month, with the copy used each time."
21339
+ },
21340
+ {
21341
+ name: "Organic Competitors",
21342
+ description: "List the domains competing with a target domain in Google organic search results."
21343
+ },
21344
+ {
21345
+ name: "Paid Competitors",
21346
+ description: "List the domains competing with a target domain in Google paid search results."
21347
+ },
21348
+ {
21349
+ name: "Domain PLA Keywords",
21350
+ description: "List the keywords that trigger a domain product listing ads, with the promoted product and price."
21351
+ },
21352
+ {
21353
+ name: "Domain PLA Copies",
21354
+ description: "List the unique product listing ads a domain runs, with product title, price, and shop name."
21355
+ },
21356
+ {
21357
+ name: "Domain vs. Domain",
21358
+ description: "Compare up to five domains on the keywords they rank for, returning each domain position side by side."
21359
+ },
21360
+ {
21361
+ name: "Subdomain Overview",
21362
+ description: "Get the organic and paid search totals for a subdomain in one regional database."
21363
+ },
21364
+ {
21365
+ name: "Subdomain Overview (All Databases)",
21366
+ description: "Get organic and paid search totals for a subdomain across every regional Semrush database."
21367
+ },
21368
+ {
21369
+ name: "Subdomain Overview History",
21370
+ description: "Get the historical trend of a subdomain organic and paid search totals."
21371
+ },
21372
+ {
21373
+ name: "Subdomain Organic Keywords",
21374
+ description: "List the keywords a subdomain ranks for in Google organic search."
21375
+ },
21376
+ {
21377
+ name: "Subdomain Paid Keywords",
21378
+ description: "List the keywords a subdomain buys in Google Ads."
21379
+ },
21380
+ {
21381
+ name: "Subdomain Ad Copies",
21382
+ description: "List the unique Google Ads creatives a subdomain runs."
21383
+ },
21384
+ {
21385
+ name: "URL Overview",
21386
+ description: "Get the organic and paid search totals for a single URL in one regional database."
21387
+ },
21388
+ {
21389
+ name: "URL Overview (All Databases)",
21390
+ description: "Get organic and paid search totals for a single URL across every regional Semrush database."
21391
+ },
21392
+ {
21393
+ name: "URL Overview History",
21394
+ description: "Get the historical trend of a URL organic and paid search totals."
21395
+ },
21396
+ {
21397
+ name: "URL Organic Keywords",
21398
+ description: "List the keywords a single URL ranks for in Google organic search."
21399
+ },
21400
+ {
21401
+ name: "URL Paid Keywords",
21402
+ description: "List the keywords a single URL is advertised on in Google Ads, with the ad copy used."
21403
+ },
21404
+ {
21405
+ name: "Keyword Overview",
21406
+ description: "Get search volume, CPC, competition, difficulty, and intent for a single keyword."
21407
+ },
21408
+ {
21409
+ name: "Keyword Overview (All Databases)",
21410
+ description: "Get search volume, CPC, and competition for a keyword across every regional Semrush database."
21411
+ },
21412
+ {
21413
+ name: "Batch Keyword Overview",
21414
+ description: "Get search volume, CPC, competition, difficulty, and intent for up to 100 keywords at once."
21415
+ },
21416
+ {
21417
+ name: "Keyword Difficulty",
21418
+ description: "Get the Keyword Difficulty Index for up to 100 keywords at once."
21419
+ },
21420
+ {
21421
+ name: "Related Keywords",
21422
+ description: "Find keywords semantically related to a seed keyword, with volume, difficulty, and relevance."
21423
+ },
21424
+ {
21425
+ name: "Broad Match Keywords",
21426
+ description: "Find broad-match and phrase-match variations of a seed keyword, with volume and difficulty."
21427
+ },
21428
+ {
21429
+ name: "Keyword Questions",
21430
+ description: "Find question-form keywords containing a seed keyword, with volume and difficulty."
21431
+ },
21432
+ {
21433
+ name: "Organic Results",
21434
+ description: "List the domains and URLs ranking in Google organic search results for a keyword."
21435
+ },
21436
+ {
21437
+ name: "Paid Results",
21438
+ description: "List the domains and URLs advertising on a keyword in Google paid search results."
21439
+ },
21440
+ {
21441
+ name: "Keyword Ad History",
21442
+ description: "List which domains advertised on a keyword month by month, with the copy each one used."
21443
+ },
21444
+ {
21445
+ name: "Winners and Losers",
21446
+ description: "List the domains that gained or lost the most organic and paid search visibility in a database."
21447
+ },
21448
+ {
21449
+ name: "Top Domains",
21450
+ description: "List the highest-ranked domains in a regional database by Semrush rank."
21451
+ },
21452
+ {
21453
+ name: "Backlinks Overview",
21454
+ description: "Get the Authority Score and backlink profile totals for a domain, subdomain, or URL."
21455
+ },
21456
+ {
21457
+ name: "Backlinks",
21458
+ description: "List the backlinks pointing at a domain, subdomain, or URL, with source page, anchor, and authority."
21459
+ },
21460
+ {
21461
+ name: "Referring Domains",
21462
+ description: "List the domains linking to a target, with Authority Score, backlink count, and country."
21463
+ },
21464
+ {
21465
+ name: "Referring IPs",
21466
+ description: "List the IP addresses linking to a target, with the domain and backlink counts behind each one."
21467
+ },
21468
+ {
21469
+ name: "Backlink TLD Distribution",
21470
+ description: "Break a target backlink profile down by the top-level domain of its referring domains."
21471
+ },
21472
+ {
21473
+ name: "Backlink Country Distribution",
21474
+ description: "Break a target backlink profile down by the country of its referring domains."
21475
+ },
21476
+ {
21477
+ name: "Backlink Anchors",
21478
+ description: "List the anchor texts used in backlinks to a target, with domain and backlink counts."
21479
+ },
21480
+ {
21481
+ name: "Indexed Pages",
21482
+ description: "List the pages of a target that attract backlinks, with response code and link counts."
21483
+ },
21484
+ {
21485
+ name: "Backlink Competitors",
21486
+ description: "List domains with a backlink profile similar to the target, ranked by shared referring domains."
21487
+ }
21488
+ ],
21489
+ operationCount: 44,
21490
+ triggers: [],
21491
+ triggerCount: 0,
21492
+ authType: "api-key",
21493
+ category: "tools",
21494
+ integrationType: "analytics",
21495
+ tags: ["seo", "marketing", "data-analytics"]
21496
+ },
21249
21497
  {
21250
21498
  type: "sendblue",
21251
21499
  slug: "sendblue",
@@ -21989,7 +22237,7 @@ var init_integrations = __esm(() => {
21989
22237
  tags: ["enrichment", "sales-engagement"]
21990
22238
  },
21991
22239
  {
21992
- type: "slack",
22240
+ type: "slack_v2",
21993
22241
  slug: "slack",
21994
22242
  name: "Slack",
21995
22243
  description: "Send, update, delete messages, manage views and modals, add or remove reactions, manage canvases, get channel info and user presence in Slack",
@@ -22170,9 +22418,9 @@ var init_integrations = __esm(() => {
22170
22418
  operationCount: 42,
22171
22419
  triggers: [
22172
22420
  {
22173
- id: "slack_webhook",
22174
- name: "Slack Webhook",
22175
- description: "Trigger workflow from Slack events like mentions, messages, and reactions"
22421
+ id: "slack_oauth",
22422
+ name: "Slack",
22423
+ description: "Trigger from Slack events (mentions, messages, reactions)"
22176
22424
  }
22177
22425
  ],
22178
22426
  triggerCount: 1,
@@ -27115,7 +27363,6 @@ var DEPLOYMENT_REQUIREMENT_BY_OAUTH_SERVICE_ID, SERVICE_ACCOUNT_METADATA_BY_OAUT
27115
27363
  var init_service_account_metadata = __esm(() => {
27116
27364
  init_service_account_providers_generated();
27117
27365
  DEPLOYMENT_REQUIREMENT_BY_OAUTH_SERVICE_ID = {
27118
- slack: "preview-gated",
27119
27366
  trello: "oauth-client"
27120
27367
  };
27121
27368
  SERVICE_ACCOUNT_METADATA_BY_OAUTH_SERVICE_ID = buildServiceAccountMetadata();
@@ -30843,6 +31090,7 @@ var init_twins = __esm(() => {
30843
31090
  { server: "ORGANIZATIONS_ENABLED", client: "NEXT_PUBLIC_ORGANIZATIONS_ENABLED" },
30844
31091
  { server: "WHITELABELING_ENABLED", client: "NEXT_PUBLIC_WHITELABELING_ENABLED" },
30845
31092
  { server: "AUDIT_LOGS_ENABLED", client: "NEXT_PUBLIC_AUDIT_LOGS_ENABLED" },
31093
+ { server: "CUSTOM_BLOCKS_ENABLED", client: "NEXT_PUBLIC_CUSTOM_BLOCKS_ENABLED" },
30846
31094
  { server: "DATA_RETENTION_ENABLED", client: "NEXT_PUBLIC_DATA_RETENTION_ENABLED" },
30847
31095
  { server: "SESSION_POLICIES_ENABLED", client: "NEXT_PUBLIC_SESSION_POLICIES_ENABLED" },
30848
31096
  { server: "DATA_DRAINS_ENABLED", client: "NEXT_PUBLIC_DATA_DRAINS_ENABLED" },
@@ -30853,7 +31101,7 @@ var init_twins = __esm(() => {
30853
31101
  { server: "SSO_ENABLED", client: "NEXT_PUBLIC_SSO_ENABLED" },
30854
31102
  { server: "EMAIL_PASSWORD_SIGNUP_ENABLED", client: "NEXT_PUBLIC_EMAIL_PASSWORD_SIGNUP_ENABLED" },
30855
31103
  { server: "E2B_ENABLED", client: "NEXT_PUBLIC_E2B_ENABLED" },
30856
- { server: "DEPLOY_AS_BLOCK", client: "NEXT_PUBLIC_CUSTOM_BLOCKS_ENABLED" }
31104
+ { server: "SLACK_EXTENDED_SCOPES", client: "NEXT_PUBLIC_SLACK_EXTENDED_SCOPES" }
30857
31105
  ];
30858
31106
  SELF_HOST_UNLOCKS = [
30859
31107
  {
@@ -30868,17 +31116,13 @@ var init_twins = __esm(() => {
30868
31116
  },
30869
31117
  { server: "ORGANIZATIONS_ENABLED", label: "Organizations", hint: "multi-workspace orgs" },
30870
31118
  { server: "AUDIT_LOGS_ENABLED", label: "Audit logs", hint: "" },
31119
+ { server: "CUSTOM_BLOCKS_ENABLED", label: "Custom blocks", hint: "reusable org-wide blocks" },
30871
31120
  { server: "DATA_RETENTION_ENABLED", label: "Data retention", hint: "deletes expired data" },
30872
31121
  { server: "SESSION_POLICIES_ENABLED", label: "Session policies", hint: "session lifetime caps" },
30873
31122
  { server: "DATA_DRAINS_ENABLED", label: "Data drains", hint: "export streams" },
30874
31123
  { server: "FORKING_ENABLED", label: "Workflow forking", hint: "" },
30875
31124
  { server: "INBOX_ENABLED", label: "Inbox", hint: "" },
30876
- { server: "WHITELABELING_ENABLED", label: "Whitelabeling", hint: "custom branding" },
30877
- {
30878
- server: "DEPLOY_AS_BLOCK",
30879
- label: "Deploy as block",
30880
- hint: "publish workflows as reusable blocks"
30881
- }
31125
+ { server: "WHITELABELING_ENABLED", label: "Whitelabeling", hint: "custom branding" }
30882
31126
  ];
30883
31127
  LOGIN_PROVIDERS = [
30884
31128
  { id: "google", label: "Google", idKey: "GOOGLE_CLIENT_ID", secretKey: "GOOGLE_CLIENT_SECRET" },
@@ -31249,14 +31493,6 @@ function checkCoherence(ctx) {
31249
31493
  });
31250
31494
  }
31251
31495
  }
31252
- if (isTruthy(sim.vars.get("PII_GRANULAR_REDACTION")) && !isTruthy(sim.vars.get("PII_REDACTION"))) {
31253
- findings.push({
31254
- group: "coherence",
31255
- status: "warn",
31256
- message: "PII_GRANULAR_REDACTION is on but PII_REDACTION is off — the granular flag is inert without it",
31257
- fix: "set PII_REDACTION=true or remove PII_GRANULAR_REDACTION"
31258
- });
31259
- }
31260
31496
  if (Boolean(sim.vars.get("TURNSTILE_SECRET_KEY")) !== Boolean(sim.vars.get("NEXT_PUBLIC_TURNSTILE_SITE_KEY"))) {
31261
31497
  findings.push({
31262
31498
  group: "coherence",
@@ -35870,6 +36106,178 @@ var init_feature_setup = __esm(() => {
35870
36106
  init_theme();
35871
36107
  });
35872
36108
 
36109
+ // src/urls.ts
36110
+ var APP_URL = "http://localhost:3000", APP_SIGNUP_URL;
36111
+ var init_urls = __esm(() => {
36112
+ APP_SIGNUP_URL = `${APP_URL}/signup`;
36113
+ });
36114
+
36115
+ // src/desktop.ts
36116
+ var exports_desktop = {};
36117
+ __export(exports_desktop, {
36118
+ sanitizeForTerminal: () => sanitizeForTerminal,
36119
+ runDesktop: () => runDesktop,
36120
+ resolveDeploymentUrl: () => resolveDeploymentUrl,
36121
+ probeDownload: () => probeDownload,
36122
+ describeProbe: () => describeProbe
36123
+ });
36124
+ function deploymentKey(value) {
36125
+ try {
36126
+ return new URL(value).origin.toLowerCase();
36127
+ } catch {
36128
+ return value;
36129
+ }
36130
+ }
36131
+ function sanitizeForTerminal(value) {
36132
+ const printable = value.replace(/\p{C}/gu, "").replace(/\p{Z}/gu, " ").replace(/ {2,}/g, " ").trim();
36133
+ return truncate(printable, MAX_INSTALLER_NAME);
36134
+ }
36135
+ function resolveDeploymentUrl(sources, override) {
36136
+ const discovered = sources.flatMap((source) => {
36137
+ const value = source.values?.get(APP_URL_KEY)?.trim();
36138
+ return value ? [{ label: source.label ?? "configuration", value }] : [];
36139
+ });
36140
+ const byDeployment = new Map;
36141
+ for (const { value } of discovered) {
36142
+ byDeployment.set(deploymentKey(value), value);
36143
+ }
36144
+ if (!override && byDeployment.size > 1) {
36145
+ throw new SetupError(`Found ${byDeployment.size} configurations naming different ${APP_URL_KEY} values.`, [
36146
+ ...discovered.map(({ label, value }) => `${label}: ${value}`),
36147
+ "Re-run with --url <deployment url> to say which one the desktop app should use."
36148
+ ]);
36149
+ }
36150
+ const raw = override ?? byDeployment.values().next().value;
36151
+ if (!raw) {
36152
+ return APP_URL;
36153
+ }
36154
+ let url;
36155
+ try {
36156
+ url = new URL(raw.trim());
36157
+ } catch {
36158
+ throw new SetupError(`${APP_URL_KEY} is not a valid URL: ${raw}`, [
36159
+ "Set it to the origin browsers use to reach Sim, e.g. https://sim.example.com"
36160
+ ]);
36161
+ }
36162
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
36163
+ throw new SetupError(`${APP_URL_KEY} must be an http(s) URL: ${raw}`);
36164
+ }
36165
+ return url.origin;
36166
+ }
36167
+ async function probeDownload(downloadUrl, fetchImpl = fetch) {
36168
+ let response;
36169
+ try {
36170
+ response = await fetchImpl(downloadUrl, {
36171
+ redirect: "manual",
36172
+ signal: AbortSignal.timeout(PROBE_TIMEOUT_MS)
36173
+ });
36174
+ } catch (error) {
36175
+ return { status: "unreachable", error: getErrorMessage(error, "request failed") };
36176
+ }
36177
+ if (REDIRECT_STATUSES.has(response.status)) {
36178
+ const location = response.headers.get("location");
36179
+ if (!location)
36180
+ return { status: "unexpected", code: response.status };
36181
+ let name = location;
36182
+ try {
36183
+ name = decodeURIComponent(new URL(location).pathname.split("/").pop() ?? location);
36184
+ } catch {}
36185
+ return { status: "ok", installerUrl: location, installerName: sanitizeForTerminal(name) };
36186
+ }
36187
+ if (response.status === 404)
36188
+ return { status: "no-release" };
36189
+ if (response.status === 502)
36190
+ return { status: "feed-unavailable" };
36191
+ return { status: "unexpected", code: response.status };
36192
+ }
36193
+ function describeProbe(probe, appUrl) {
36194
+ switch (probe.status) {
36195
+ case "ok":
36196
+ return { headline: `${glyph.pass} Installer resolved: ${probe.installerName}`, hints: [] };
36197
+ case "no-release":
36198
+ return {
36199
+ headline: `${glyph.fail} This deployment reports no desktop release for its channel.`,
36200
+ hints: [
36201
+ "Stable desktop builds are published on GitHub releases of simstudioai/sim.",
36202
+ "A brand-new fork with no releases of its own will report this."
36203
+ ]
36204
+ };
36205
+ case "feed-unavailable":
36206
+ return {
36207
+ headline: `${glyph.fail} The deployment could not reach the GitHub release feed.`,
36208
+ hints: [
36209
+ "The Sim server needs outbound access to api.github.com and github.com.",
36210
+ "Unauthenticated GitHub API calls are capped at 60/hour per IP — set GITHUB_TOKEN on the Sim server to raise it to 5000/hour."
36211
+ ]
36212
+ };
36213
+ case "unreachable":
36214
+ return {
36215
+ headline: `${glyph.fail} Could not reach ${appUrl} — ${probe.error}`,
36216
+ hints: [
36217
+ `Check that Sim is running and reachable at ${appUrl} (npx sim-setup status).`,
36218
+ "Pass --url if this machine reaches Sim at a different address."
36219
+ ]
36220
+ };
36221
+ case "unexpected":
36222
+ return { headline: `${glyph.fail} The download endpoint answered ${probe.code}.`, hints: [] };
36223
+ }
36224
+ }
36225
+ async function runDesktop(flags) {
36226
+ const appUrl = resolveDeploymentUrl(flags.url ? [] : discoverConfigurationSources(), flags.url);
36227
+ const downloadUrl = `${appUrl}${DOWNLOAD_PATH}`;
36228
+ log2.step(`Deployment: ${theme.accent(appUrl)}`);
36229
+ const spin = spinner2();
36230
+ spin.start("Resolving the desktop installer…");
36231
+ const [probe, feedOk] = await Promise.all([
36232
+ probeDownload(downloadUrl),
36233
+ httpHealth(`${appUrl}${FEED_PATH}`, PROBE_TIMEOUT_MS)
36234
+ ]);
36235
+ const { headline, hints } = describeProbe(probe, appUrl);
36236
+ spin.stop(headline);
36237
+ if (probe.status !== "ok") {
36238
+ for (const hint of hints) {
36239
+ log2.info(hint);
36240
+ }
36241
+ outro2(theme.error("The desktop installer could not be resolved."));
36242
+ return 1;
36243
+ }
36244
+ if (!feedOk) {
36245
+ log2.warn(`${FEED_PATH} did not resolve — the app will install but will not auto-update from this deployment.`);
36246
+ }
36247
+ note2([
36248
+ `1. Download and install Sim:`,
36249
+ ` ${theme.accent(downloadUrl)}`,
36250
+ "",
36251
+ `2. Open Sim, then choose ${theme.command("Sim → Server…")} in the menu bar.`,
36252
+ "",
36253
+ `3. Enter your server URL and press Connect:`,
36254
+ ` ${theme.accent(appUrl)}`,
36255
+ "",
36256
+ theme.muted("Sim relaunches against your deployment and updates from it from then on."),
36257
+ theme.muted("The desktop app is macOS-only today; the web app works everywhere.")
36258
+ ].join(`
36259
+ `), "Connect the desktop app");
36260
+ if (!flags.noOpen) {
36261
+ if (await confirm2({ message: "Download it now?", initialValue: true })) {
36262
+ openBrowser(downloadUrl);
36263
+ }
36264
+ }
36265
+ outro2(theme.accent("Ready."));
36266
+ return 0;
36267
+ }
36268
+ var DOWNLOAD_PATH = "/api/desktop/update/download", FEED_PATH = "/api/desktop/update/latest-mac.yml", PROBE_TIMEOUT_MS = 15000, REDIRECT_STATUSES, APP_URL_KEY = "NEXT_PUBLIC_APP_URL", MAX_INSTALLER_NAME = 120;
36269
+ var init_desktop = __esm(() => {
36270
+ init_string();
36271
+ init_cli_auth();
36272
+ init_configuration_sources();
36273
+ init_errors();
36274
+ init_probes();
36275
+ init_prompter();
36276
+ init_theme();
36277
+ init_urls();
36278
+ REDIRECT_STATUSES = new Set([301, 302, 307, 308]);
36279
+ });
36280
+
35873
36281
  // src/doctor.ts
35874
36282
  var exports_doctor = {};
35875
36283
  __export(exports_doctor, {
@@ -36131,12 +36539,6 @@ var init_docker = __esm(() => {
36131
36539
  APP_DIRS = ["/Applications", join(homedir(), "Applications")];
36132
36540
  });
36133
36541
 
36134
- // src/urls.ts
36135
- var APP_URL = "http://localhost:3000", APP_SIGNUP_URL;
36136
- var init_urls = __esm(() => {
36137
- APP_SIGNUP_URL = `${APP_URL}/signup`;
36138
- });
36139
-
36140
36542
  // src/modes/k8s.ts
36141
36543
  import { spawn, spawnSync as spawnSync6 } from "node:child_process";
36142
36544
  function run(command, args, failMessage, input) {
@@ -38024,24 +38426,31 @@ function oneFlag(args, flag) {
38024
38426
  fail(`${flag} may only be provided once`);
38025
38427
  return count === 1;
38026
38428
  }
38027
- function parseMode(args) {
38028
- let mode;
38429
+ function parseValueOption(args, flag, requirement) {
38430
+ let value;
38029
38431
  const remaining = [];
38432
+ const prefix = `${flag}=`;
38030
38433
  for (let index = 0;index < args.length; index += 1) {
38031
38434
  const arg = args[index];
38032
- if (arg !== "--mode" && !arg.startsWith("--mode=")) {
38435
+ if (arg !== flag && !arg.startsWith(prefix)) {
38033
38436
  remaining.push(arg);
38034
38437
  continue;
38035
38438
  }
38036
- if (mode)
38037
- fail("--mode may only be provided once");
38038
- const value = arg === "--mode" ? args[++index] : arg.slice("--mode=".length);
38039
- if (value !== "compose" && value !== "dev" && value !== "k8s") {
38040
- fail(`invalid --mode "${value ?? ""}" — expected compose, dev, or k8s`);
38041
- }
38042
- mode = value;
38439
+ if (value !== undefined)
38440
+ fail(`${flag} may only be provided once`);
38441
+ const candidate = arg === flag ? args[++index] : arg.slice(prefix.length);
38442
+ if (!candidate || candidate.startsWith("-"))
38443
+ fail(requirement);
38444
+ value = candidate;
38043
38445
  }
38044
- return { mode, remaining };
38446
+ return { value, remaining };
38447
+ }
38448
+ function parseMode(args) {
38449
+ const { value, remaining } = parseValueOption(args, "--mode", "--mode requires a value");
38450
+ if (value !== undefined && value !== "compose" && value !== "dev" && value !== "k8s") {
38451
+ fail(`invalid --mode "${value}" — expected compose, dev, or k8s`);
38452
+ }
38453
+ return { mode: value, remaining };
38045
38454
  }
38046
38455
  function expectNoArguments(command, args) {
38047
38456
  if (args.length > 0)
@@ -38084,6 +38493,13 @@ function parseCore(args, helpRequested) {
38084
38493
  }
38085
38494
  return { kind: "add", feature, args: featureArgs };
38086
38495
  }
38496
+ if (command === "desktop") {
38497
+ const noOpen = oneFlag(commandArgs, "--no-open");
38498
+ const { value: url, remaining } = parseValueOption(commandArgs.filter((arg) => arg !== "--no-open"), "--url", "--url requires a deployment URL");
38499
+ if (remaining.length > 0)
38500
+ fail(`Unknown desktop option: ${remaining[0]}`);
38501
+ return { kind: "desktop", noOpen, ...url ? { url } : {} };
38502
+ }
38087
38503
  if (command === "doctor") {
38088
38504
  const fix = oneFlag(commandArgs, "--fix");
38089
38505
  const json = oneFlag(commandArgs, "--json");
@@ -38128,6 +38544,7 @@ var USAGE = `Usage:
38128
38544
  sim-setup [--quick] [--dir <path>] [--mode compose|dev|k8s]
38129
38545
  sim-setup config show configured capabilities and integrations
38130
38546
  sim-setup add <feature> configure ${SETUP_FEATURES2}
38547
+ sim-setup desktop [--url <url>] install the macOS desktop app against this deployment
38131
38548
  sim-setup doctor [--fix] [--json] check your setup
38132
38549
  sim-setup start | stop | restart bring your install up / down / cycle
38133
38550
  sim-setup update pull/rebuild and apply Compose images
@@ -38158,6 +38575,11 @@ async function main() {
38158
38575
  await runFeatureSetup2(invocation.feature, invocation.args);
38159
38576
  return;
38160
38577
  }
38578
+ if (invocation.kind === "desktop") {
38579
+ const { runDesktop: runDesktop2 } = await Promise.resolve().then(() => (init_desktop(), exports_desktop));
38580
+ process.exitCode = await runDesktop2({ url: invocation.url, noOpen: invocation.noOpen });
38581
+ return;
38582
+ }
38161
38583
  if (invocation.kind === "doctor") {
38162
38584
  const { runDoctor: runDoctor2 } = await Promise.resolve().then(() => (init_doctor(), exports_doctor));
38163
38585
  process.exitCode = await runDoctor2({ fix: invocation.fix, json: invocation.json });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sim-setup",
3
- "version": "1.0.2",
3
+ "version": "1.0.3-preview.50.1",
4
4
  "description": "Set up and manage a self-hosted Sim installation",
5
5
  "type": "module",
6
6
  "bin": {