caraer-cli 0.1.2__py3-none-any.whl
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.
- caraer_cli/__init__.py +4 -0
- caraer_cli/api/__init__.py +1 -0
- caraer_cli/api/apps.py +78 -0
- caraer_cli/api/auth.py +53 -0
- caraer_cli/api/client.py +179 -0
- caraer_cli/api/functions.py +72 -0
- caraer_cli/api/installation.py +93 -0
- caraer_cli/api/integration_runtime.py +77 -0
- caraer_cli/api/projects.py +213 -0
- caraer_cli/api/sandboxes.py +29 -0
- caraer_cli/api/webhooks.py +59 -0
- caraer_cli/app_sync.py +697 -0
- caraer_cli/apps_local.py +274 -0
- caraer_cli/commands/__init__.py +1 -0
- caraer_cli/commands/apps.py +2025 -0
- caraer_cli/commands/auth.py +173 -0
- caraer_cli/commands/company.py +68 -0
- caraer_cli/commands/installation.py +182 -0
- caraer_cli/commands/profile.py +239 -0
- caraer_cli/commands/publish.py +40 -0
- caraer_cli/commands/sandbox.py +92 -0
- caraer_cli/commands/skill.py +165 -0
- caraer_cli/commands/webhooks.py +68 -0
- caraer_cli/completion.py +77 -0
- caraer_cli/completion_callbacks.py +162 -0
- caraer_cli/context.py +41 -0
- caraer_cli/errors.py +84 -0
- caraer_cli/formatters/__init__.py +1 -0
- caraer_cli/formatters/output.py +381 -0
- caraer_cli/formatters/timestamps.py +98 -0
- caraer_cli/install_completion.py +38 -0
- caraer_cli/local_app.py +135 -0
- caraer_cli/main.py +104 -0
- caraer_cli/models/__init__.py +1 -0
- caraer_cli/models/api.py +52 -0
- caraer_cli/project/__init__.py +17 -0
- caraer_cli/project/app_bars_sync.py +154 -0
- caraer_cli/project/app_manifest_template.py +68 -0
- caraer_cli/project/inbound_sync.py +192 -0
- caraer_cli/project/json_schemas.py +66 -0
- caraer_cli/project/lifecycle_sync.py +119 -0
- caraer_cli/project/local_dev.py +825 -0
- caraer_cli/project/manifest_edit.py +51 -0
- caraer_cli/project/marketplace_assemble.py +165 -0
- caraer_cli/project/oauth_providers_sync.py +180 -0
- caraer_cli/project/paths.py +102 -0
- caraer_cli/project/pricing_sync.py +81 -0
- caraer_cli/project/push_plan.py +590 -0
- caraer_cli/project/release.py +128 -0
- caraer_cli/project/scaffold.py +537 -0
- caraer_cli/project/schedules_sync.py +170 -0
- caraer_cli/project/schema.py +160 -0
- caraer_cli/project/settings_sync.py +77 -0
- caraer_cli/project/state.py +51 -0
- caraer_cli/project/sync.py +308 -0
- caraer_cli/project/typegen.py +278 -0
- caraer_cli/project/validate_app.py +1215 -0
- caraer_cli/project/webhooks_sync.py +233 -0
- caraer_cli/resolve.py +55 -0
- caraer_cli/schemas/app.caraer.schema.json +175 -0
- caraer_cli/schemas/function.caraer.schema.json +29 -0
- caraer_cli/schemas/inbound.caraer.schema.json +49 -0
- caraer_cli/schemas/lifecycle.caraer.schema.json +50 -0
- caraer_cli/schemas/schedule.caraer.schema.json +39 -0
- caraer_cli/schemas/webhook.caraer.schema.json +50 -0
- caraer_cli/skills/.gitkeep +2 -0
- caraer_cli/skills/caraer-apps/SKILL.md +172 -0
- caraer_cli/skills/caraer-apps/reference.md +163 -0
- caraer_cli/state/__init__.py +1 -0
- caraer_cli/state/config.py +148 -0
- caraer_cli/state/session.py +98 -0
- caraer_cli/utils.py +40 -0
- caraer_cli/wizard/__init__.py +9 -0
- caraer_cli/wizard/catalog.py +170 -0
- caraer_cli/wizard/marketplace.py +350 -0
- caraer_cli/wizard/prompts.py +99 -0
- caraer_cli/wizard/public_app.py +519 -0
- caraer_cli/wizard/scope_macros.py +214 -0
- caraer_cli-0.1.2.dist-info/METADATA +266 -0
- caraer_cli-0.1.2.dist-info/RECORD +83 -0
- caraer_cli-0.1.2.dist-info/WHEEL +4 -0
- caraer_cli-0.1.2.dist-info/entry_points.txt +2 -0
- caraer_cli-0.1.2.dist-info/licenses/LICENSE +8 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"""Public-app scope macro catalog (mirrors the Caraer creator / backend)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class ScopeMacroPreset:
|
|
10
|
+
"""A supported creator-side scope macro pattern."""
|
|
11
|
+
|
|
12
|
+
id: str
|
|
13
|
+
title: str
|
|
14
|
+
pattern: str
|
|
15
|
+
example: str
|
|
16
|
+
description: str
|
|
17
|
+
when_to_use: str
|
|
18
|
+
needs_tool: bool = False
|
|
19
|
+
needs_object: bool = False
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
SCOPE_MACRO_PRESETS: tuple[ScopeMacroPreset, ...] = (
|
|
23
|
+
ScopeMacroPreset(
|
|
24
|
+
id="global.all",
|
|
25
|
+
title="All global scopes",
|
|
26
|
+
pattern="global.all",
|
|
27
|
+
example="global.all",
|
|
28
|
+
description="Expands to every scope that starts with `global.`.",
|
|
29
|
+
when_to_use=(
|
|
30
|
+
"Use when your app needs platform-wide capabilities "
|
|
31
|
+
"(not tied to a specific record)."
|
|
32
|
+
),
|
|
33
|
+
),
|
|
34
|
+
ScopeMacroPreset(
|
|
35
|
+
id="tools.tool.all",
|
|
36
|
+
title="All scopes for a tool",
|
|
37
|
+
pattern="tools.<tool>.all",
|
|
38
|
+
example="tools.forms.all",
|
|
39
|
+
description=(
|
|
40
|
+
"Expands to every scope that starts with `tools.<tool>.` "
|
|
41
|
+
"(for the concrete tool name you put in the macro)."
|
|
42
|
+
),
|
|
43
|
+
when_to_use=(
|
|
44
|
+
"Use when your app only touches one tool area, but needs the "
|
|
45
|
+
"full set of that tool's scopes."
|
|
46
|
+
),
|
|
47
|
+
needs_tool=True,
|
|
48
|
+
),
|
|
49
|
+
ScopeMacroPreset(
|
|
50
|
+
id="records.object.all",
|
|
51
|
+
title="Record-level scopes for one object",
|
|
52
|
+
pattern="records.<object>.all",
|
|
53
|
+
example="records.candidate.all",
|
|
54
|
+
description=(
|
|
55
|
+
"Expands to record-level scopes for `<object>`, excluding "
|
|
56
|
+
"`.property.` and `.relation.` scopes."
|
|
57
|
+
),
|
|
58
|
+
when_to_use=(
|
|
59
|
+
"Use when your app reads/writes a record, but does not need to "
|
|
60
|
+
"manage specific properties or relations."
|
|
61
|
+
),
|
|
62
|
+
needs_object=True,
|
|
63
|
+
),
|
|
64
|
+
ScopeMacroPreset(
|
|
65
|
+
id="records.*.all",
|
|
66
|
+
title="Record-level scopes for all objects",
|
|
67
|
+
pattern="records.*.all",
|
|
68
|
+
example="records.*.all",
|
|
69
|
+
description=(
|
|
70
|
+
"Expands to every record-level scope in the tenant catalog "
|
|
71
|
+
"(excludes `.property.` and `.relation.`)."
|
|
72
|
+
),
|
|
73
|
+
when_to_use=(
|
|
74
|
+
"Use with care. It usually grants broad access across many "
|
|
75
|
+
"record types."
|
|
76
|
+
),
|
|
77
|
+
),
|
|
78
|
+
ScopeMacroPreset(
|
|
79
|
+
id="records.object.properties_all",
|
|
80
|
+
title="Property scopes for one object",
|
|
81
|
+
pattern="records.<object>.properties_all",
|
|
82
|
+
example="records.candidate.properties_all",
|
|
83
|
+
description="Expands to all `.property.` scopes for `<object>`.",
|
|
84
|
+
when_to_use=(
|
|
85
|
+
"Use when your app needs to manage or validate specific fields "
|
|
86
|
+
"on a record."
|
|
87
|
+
),
|
|
88
|
+
needs_object=True,
|
|
89
|
+
),
|
|
90
|
+
ScopeMacroPreset(
|
|
91
|
+
id="records.*.properties_all",
|
|
92
|
+
title="Property scopes for all objects",
|
|
93
|
+
pattern="records.*.properties_all",
|
|
94
|
+
example="records.*.properties_all",
|
|
95
|
+
description="Expands to all `.property.` scopes for every record object.",
|
|
96
|
+
when_to_use=(
|
|
97
|
+
"Use with care if you only need a subset of properties; prefer "
|
|
98
|
+
"the `<object>` variant."
|
|
99
|
+
),
|
|
100
|
+
),
|
|
101
|
+
ScopeMacroPreset(
|
|
102
|
+
id="records.object.relations_all",
|
|
103
|
+
title="Relation scopes for one object",
|
|
104
|
+
pattern="records.<object>.relations_all",
|
|
105
|
+
example="records.candidate.relations_all",
|
|
106
|
+
description="Expands to all `.relation.` scopes for `<object>`.",
|
|
107
|
+
when_to_use=(
|
|
108
|
+
"Use when your app works with relations between records "
|
|
109
|
+
"(e.g. linked entities)."
|
|
110
|
+
),
|
|
111
|
+
needs_object=True,
|
|
112
|
+
),
|
|
113
|
+
ScopeMacroPreset(
|
|
114
|
+
id="records.*.relations_all",
|
|
115
|
+
title="Relation scopes for all objects",
|
|
116
|
+
pattern="records.*.relations_all",
|
|
117
|
+
example="records.*.relations_all",
|
|
118
|
+
description="Expands to all `.relation.` scopes for every record object.",
|
|
119
|
+
when_to_use=(
|
|
120
|
+
"Use with care; relation access can be broad and may unlock "
|
|
121
|
+
"many actions."
|
|
122
|
+
),
|
|
123
|
+
),
|
|
124
|
+
ScopeMacroPreset(
|
|
125
|
+
id="records.object.pack",
|
|
126
|
+
title="Full pack for one object (all + properties + relations)",
|
|
127
|
+
pattern="records.<object>.{all,properties_all,relations_all}",
|
|
128
|
+
example="records.candidate.all + properties_all + relations_all",
|
|
129
|
+
description=(
|
|
130
|
+
"Adds the three common macros for one object in one step: "
|
|
131
|
+
"`records.<object>.all`, `.properties_all`, and `.relations_all`."
|
|
132
|
+
),
|
|
133
|
+
when_to_use=(
|
|
134
|
+
"Recommended when your app fully works with one record type."
|
|
135
|
+
),
|
|
136
|
+
needs_object=True,
|
|
137
|
+
),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
KNOWN_TOOL_NAMES: tuple[str, ...] = (
|
|
141
|
+
"apps",
|
|
142
|
+
"automations",
|
|
143
|
+
"company_settings",
|
|
144
|
+
"environments",
|
|
145
|
+
"forms",
|
|
146
|
+
"files",
|
|
147
|
+
"modules",
|
|
148
|
+
"objects_schemas",
|
|
149
|
+
"users",
|
|
150
|
+
"views",
|
|
151
|
+
"web_menus",
|
|
152
|
+
"previews",
|
|
153
|
+
"sync",
|
|
154
|
+
"feeds",
|
|
155
|
+
"analytics",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
COMMON_OBJECT_NAMES: tuple[str, ...] = (
|
|
159
|
+
"candidate",
|
|
160
|
+
"contact",
|
|
161
|
+
"vacancy",
|
|
162
|
+
"application",
|
|
163
|
+
"company",
|
|
164
|
+
"person",
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
EXACT_SCOPE_EXAMPLES: tuple[str, ...] = (
|
|
168
|
+
"tools.apps.read",
|
|
169
|
+
"tools.apps.write",
|
|
170
|
+
"tools.forms.read",
|
|
171
|
+
"tools.forms.write",
|
|
172
|
+
"tools.objects_schemas.read",
|
|
173
|
+
"tools.objects_schemas.write",
|
|
174
|
+
"tools.files.read",
|
|
175
|
+
"tools.files.write",
|
|
176
|
+
"tools.automations.read",
|
|
177
|
+
"tools.automations.write",
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def find_preset(preset_id: str) -> ScopeMacroPreset | None:
|
|
182
|
+
for preset in SCOPE_MACRO_PRESETS:
|
|
183
|
+
if preset.id == preset_id:
|
|
184
|
+
return preset
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def materialize_macro(
|
|
189
|
+
preset: ScopeMacroPreset,
|
|
190
|
+
*,
|
|
191
|
+
tool: str | None = None,
|
|
192
|
+
object_name: str | None = None,
|
|
193
|
+
) -> list[str]:
|
|
194
|
+
"""Turn a macro preset into one or more concrete requiredScopes strings."""
|
|
195
|
+
if preset.id == "records.object.pack":
|
|
196
|
+
if not object_name:
|
|
197
|
+
raise ValueError("object_name is required for this macro")
|
|
198
|
+
obj = object_name.strip()
|
|
199
|
+
return [
|
|
200
|
+
f"records.{obj}.all",
|
|
201
|
+
f"records.{obj}.properties_all",
|
|
202
|
+
f"records.{obj}.relations_all",
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
pattern = preset.pattern
|
|
206
|
+
if preset.needs_tool:
|
|
207
|
+
if not tool:
|
|
208
|
+
raise ValueError("tool is required for this macro")
|
|
209
|
+
pattern = pattern.replace("<tool>", tool.strip())
|
|
210
|
+
if preset.needs_object:
|
|
211
|
+
if not object_name:
|
|
212
|
+
raise ValueError("object_name is required for this macro")
|
|
213
|
+
pattern = pattern.replace("<object>", object_name.strip())
|
|
214
|
+
return [pattern]
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: caraer-cli
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: Developer CLI for Caraer apps, webhooks, and serverless functions.
|
|
5
|
+
Project-URL: Homepage, https://caraer.com
|
|
6
|
+
Project-URL: Documentation, https://developer.caraer.com
|
|
7
|
+
Author: Caraer
|
|
8
|
+
License: Proprietary
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: apps,caraer,cli,marketplace,serverless
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: Other/Proprietary License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: httpx>=0.27.0
|
|
22
|
+
Requires-Dist: keyring>=25.2.1
|
|
23
|
+
Requires-Dist: platformdirs>=4.2.2
|
|
24
|
+
Requires-Dist: pydantic>=2.8.0
|
|
25
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
26
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
27
|
+
Requires-Dist: questionary>=2.0.1
|
|
28
|
+
Requires-Dist: rich>=13.7.1
|
|
29
|
+
Requires-Dist: tomli>=2.0.1; python_version < '3.11'
|
|
30
|
+
Requires-Dist: typer>=0.12.3
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: build>=1.2.1; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=8.3.2; extra == 'dev'
|
|
34
|
+
Provides-Extra: schemas
|
|
35
|
+
Requires-Dist: jsonschema>=4.22.0; extra == 'schemas'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# Caraer CLI
|
|
39
|
+
|
|
40
|
+
Standalone developer CLI for Caraer app lifecycle management.
|
|
41
|
+
|
|
42
|
+
Install and use this package independently of the Caraer backend. It talks to
|
|
43
|
+
the Caraer API as a thin client — no GCP credentials are required on your machine.
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- **Python 3.10+**
|
|
48
|
+
- A Caraer account with access to a company that can create public apps
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
### From PyPI
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pipx install caraer-cli
|
|
56
|
+
# or: uv tool install caraer-cli
|
|
57
|
+
# or: pip install caraer-cli
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Publishing (maintainers): tag `v*` runs [`.github/workflows/publish.yml`](.github/workflows/publish.yml).
|
|
61
|
+
Add a PyPI API token as the `API_TOKEN` secret on the GitHub `pypi` environment
|
|
62
|
+
(or as a repository secret with the same name).
|
|
63
|
+
|
|
64
|
+
### From source (development)
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone <this-repo> caraer-cli
|
|
68
|
+
cd caraer-cli
|
|
69
|
+
python3 -m venv .venv
|
|
70
|
+
source .venv/bin/activate
|
|
71
|
+
./scripts/install.sh # pip install + shell tab completion
|
|
72
|
+
# or: ./scripts/install.sh --shell zsh
|
|
73
|
+
caraer --help
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If install fails with `requires a different Python`, create the venv with
|
|
77
|
+
`python3.10` / `python3.11` / `python3.12` explicitly.
|
|
78
|
+
|
|
79
|
+
Tab completion is installed by `scripts/install.sh`. Restart the terminal afterward.
|
|
80
|
+
|
|
81
|
+
## AI IDEs (Cursor skill)
|
|
82
|
+
|
|
83
|
+
Ship an Agent Skill so Cursor (and similar IDEs) can scaffold and validate Caraer
|
|
84
|
+
apps correctly:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
caraer skill install # ~/.cursor/skills/caraer-apps
|
|
88
|
+
caraer skill install --project # ./.cursor/skills/caraer-apps
|
|
89
|
+
caraer skill list
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Source of truth: [`skills/caraer-apps`](skills/caraer-apps). After install, start a
|
|
93
|
+
new agent chat and ask it to create or edit a Caraer app.
|
|
94
|
+
|
|
95
|
+
## Quick start
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
caraer auth login
|
|
99
|
+
# or password/CI: caraer auth login --email you@example.com
|
|
100
|
+
caraer company list
|
|
101
|
+
caraer company select <company-uuid>
|
|
102
|
+
caraer apps list
|
|
103
|
+
caraer apps select <app-uuid> # pulls the full app folder locally
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Create a new local app and push everything in one step:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
caraer apps init --label "My App"
|
|
110
|
+
cd my_app
|
|
111
|
+
# edit src/app/app.caraer.yaml, src/app/functions/, src/app/webhooks/
|
|
112
|
+
caraer apps push --deploy # prompts for version (> previous) + release notes
|
|
113
|
+
caraer apps version # live semver + recent builds
|
|
114
|
+
caraer apps status
|
|
115
|
+
caraer apps logs # uses the only local function (or prompts)
|
|
116
|
+
caraer apps logs --all # V2 app container logs
|
|
117
|
+
caraer apps dev # local server: POST /functions/<name>
|
|
118
|
+
caraer apps test --record <uuid>
|
|
119
|
+
caraer apps state get
|
|
120
|
+
caraer apps secrets list
|
|
121
|
+
caraer apps rollback # redeploy prior READY build
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
New apps default to workspace `platformVersion: 2026.2` (App platform V2: one async
|
|
125
|
+
container runtime per app). Use `caraer apps init --platform 2026.1` only for the
|
|
126
|
+
legacy per-function Cloud Functions model. See [docs/platform_versioning.md](docs/platform_versioning.md).
|
|
127
|
+
|
|
128
|
+
`apps push` syncs the full app: marketplace manifest (including pricing + app bars),
|
|
129
|
+
functions, webhooks, schedules, inbound routes, and external OAuth providers.
|
|
130
|
+
There is no separate upload command.
|
|
131
|
+
|
|
132
|
+
Add local scaffolds inside an app folder:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
caraer apps add-function my-action
|
|
136
|
+
caraer apps add-webhook --topic record.created --function my-action
|
|
137
|
+
caraer apps add-schedule renew-watch --function my-action --cron "0 0 */6 * * *"
|
|
138
|
+
caraer apps add-inbound gmail-push --function my-action --auth SHARED_SECRET
|
|
139
|
+
caraer apps add-setting # wizard → appends to app.caraer.yaml
|
|
140
|
+
caraer apps add-pricing-plan # wizard → appends to app.caraer.yaml
|
|
141
|
+
caraer apps add-app-bar # wizard → appends to app.caraer.yaml
|
|
142
|
+
caraer apps add-lifecycle-hook # wizard → lifecycle/*.json + function
|
|
143
|
+
caraer apps add-webhook --topic app.bar.triggered --mode HTTP --url https://example.com/hook
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`add-setting` / `add-pricing-plan` / `add-app-bar` write into `app.caraer.yaml` by
|
|
147
|
+
default (use `--modular` for separate JSON files). Lifecycle hooks stay under
|
|
148
|
+
`src/app/lifecycle/` because they pair with function folders.
|
|
149
|
+
|
|
150
|
+
Lifecycle hooks (`install` / `uninstall` / `rotate` / `update`) and matching
|
|
151
|
+
`functions/on-*` folders are created automatically by `caraer apps init`.
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
Only the **app creator company** (or super-admin) can push builds for an app.
|
|
155
|
+
|
|
156
|
+
## Platform versions
|
|
157
|
+
|
|
158
|
+
| CLI `platformVersion` | App platform | Notes |
|
|
159
|
+
|-----------------------|--------------|-------|
|
|
160
|
+
| `2026.2` (default) | V2 | One container per app; async deploy; poll `runtimeStatus` |
|
|
161
|
+
| `2026.1` | V1 | One Cloud Function per serverless function (legacy) |
|
|
162
|
+
|
|
163
|
+
Migrate an existing V1 app in place with:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
caraer apps migrate-v2 [--runtime nodejs22|python312]
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This provisions the shared container, keeps webhook delivery on legacy function URLs
|
|
170
|
+
until `runtimeStatus=READY`, then updates local `caraer.json` to `2026.2`.
|
|
171
|
+
|
|
172
|
+
## Command groups
|
|
173
|
+
|
|
174
|
+
- `auth` / `company` / `profile` — session and profiles
|
|
175
|
+
- `apps` — local folder lifecycle + full sync (`pull` / `push`), builds, logs, local dev
|
|
176
|
+
- `webhooks` — formats, events, and test helpers
|
|
177
|
+
- `publish` — submit / status for marketplace review
|
|
178
|
+
- `sandbox` — clone the company Neo4j DB (same company; `X-Caraer-Sandbox-Uuid` overrides `databaseid`)
|
|
179
|
+
|
|
180
|
+
## Local app layout
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
my_app/
|
|
184
|
+
caraer.json # workspace metadata (platformVersion, appUuid, …)
|
|
185
|
+
src/app/
|
|
186
|
+
app.caraer.yaml # identity, auth, OAuth, settings, pricing, app bars
|
|
187
|
+
lifecycle/*.json # install|uninstall|rotate|update hooks
|
|
188
|
+
functions/<name>/ # function.caraer.json + entry source
|
|
189
|
+
webhooks/*.json # one webhook definition per file
|
|
190
|
+
schedules/*.json # cron → function (integration runtime)
|
|
191
|
+
inbound/*.json # public inbound routes → function
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`add-setting` / `add-pricing-plan` / `add-app-bar` append to `app.caraer.yaml`.
|
|
195
|
+
Optional modular JSON files (`settings/`, `pricing/`, `app-bars/`) still merge on
|
|
196
|
+
push when present (`--modular`). `apps init` always creates all four lifecycle
|
|
197
|
+
hooks + `on-*` functions. See [docs/app_lifecycle.md](docs/app_lifecycle.md).
|
|
198
|
+
|
|
199
|
+
See [`examples/webhook-inbox`](examples/webhook-inbox) for a minimal sample
|
|
200
|
+
(inbound route, settings, lifecycle, app bar).
|
|
201
|
+
|
|
202
|
+
## Profiles
|
|
203
|
+
|
|
204
|
+
Config lives in the user config dir (`config.toml`). Defaults include `dev`,
|
|
205
|
+
`staging`, and `prod`.
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
caraer profile list
|
|
209
|
+
caraer profile use staging
|
|
210
|
+
caraer profile set --base-url https://api.caraer.com --output json
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Override the active profile for a single command with `--profile <name>`.
|
|
214
|
+
|
|
215
|
+
For local API development against a running backend:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
caraer profile set --base-url http://localhost:8080
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Developer sandboxes
|
|
222
|
+
|
|
223
|
+
Create a Neo4j DB clone of the selected company, then activate it per request.
|
|
224
|
+
Company identity stays the same; only the Neo4j `databaseid` is overridden:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
caraer company select <owner-company-uuid>
|
|
228
|
+
caraer sandbox create --name my-test
|
|
229
|
+
caraer sandbox list
|
|
230
|
+
caraer sandbox use <sandbox-uuid> # same company; sends X-Caraer-Sandbox-Uuid
|
|
231
|
+
# … test against the clone DB …
|
|
232
|
+
caraer sandbox clear # back to the company production database
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Each company may have at most **3** active sandboxes. After a backend deploy that
|
|
236
|
+
changed the sandbox model, recreate sandboxes (old clone-company sandboxes are invalid).
|
|
237
|
+
|
|
238
|
+
Sandboxes isolate **Neo4j data only** — function runtime code is still shared with
|
|
239
|
+
production. Prefer `caraer apps push --dry-run` to preview changes, and treat
|
|
240
|
+
`--target sandbox` as a data sandbox, not a separate code environment.
|
|
241
|
+
|
|
242
|
+
## Documentation
|
|
243
|
+
|
|
244
|
+
- [Platform versioning](docs/platform_versioning.md) — V1 vs V2 runtime model
|
|
245
|
+
- [Backend contract](docs/backend_contract.md) — REST endpoints used by the CLI
|
|
246
|
+
- [Changelog](CHANGELOG.md)
|
|
247
|
+
- [Security](SECURITY.md)
|
|
248
|
+
- Cursor skill: [`skills/caraer-apps`](skills/caraer-apps) (`caraer skill install`)
|
|
249
|
+
|
|
250
|
+
## Related
|
|
251
|
+
|
|
252
|
+
- API / platform: Caraer backend
|
|
253
|
+
- Docs site: https://developer.caraer.com
|
|
254
|
+
- Example app: [`examples/webhook-inbox`](examples/webhook-inbox)
|
|
255
|
+
|
|
256
|
+
## Development / CI
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
./scripts/ci.sh
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
GitHub Actions workflow: `.github/workflows/ci.yml`
|
|
263
|
+
|
|
264
|
+
## License
|
|
265
|
+
|
|
266
|
+
Proprietary — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
caraer_cli/__init__.py,sha256=0EfcHzuDTOHWzIds-cOHP1b2yYfXpYQsoZPDG6Bxu60,86
|
|
2
|
+
caraer_cli/app_sync.py,sha256=Uch2nI6fd6umsmxf1hHsTkTLe-i4dIncYXKgZk3Cjvg,25723
|
|
3
|
+
caraer_cli/apps_local.py,sha256=bEEmoDyxCFRlVfkubKbBO8c4z-ZlT6lqHdzPu4iq_s4,9669
|
|
4
|
+
caraer_cli/completion.py,sha256=8OjhNuaF0hMV2C2ox8p1avGVptY9VOJqN1MujdkiPHs,2269
|
|
5
|
+
caraer_cli/completion_callbacks.py,sha256=XCoWI9ReYfDnxdvkN6D_suVIwI9jSGwMGekVNJ5-VaA,5747
|
|
6
|
+
caraer_cli/context.py,sha256=lUfHvKlCCTXJ6DgHW8FzCUHqtu-jPXI-IyJLkZukOAQ,1314
|
|
7
|
+
caraer_cli/errors.py,sha256=0JVOYCqqHUenNrt3RZ7-tECf14TREHpyB3V85-4DySw,2043
|
|
8
|
+
caraer_cli/install_completion.py,sha256=rXc2-vaURisS6svwj3ABfJHgHGFh4vFn5XV5FG9nerI,1132
|
|
9
|
+
caraer_cli/local_app.py,sha256=2WBtH_MpGbWF0Bk1dQhND0jHgPnJket-Vo75WjkcPgA,4452
|
|
10
|
+
caraer_cli/main.py,sha256=jTcrN2S7D7yDS5LsAinPYzkkv3isws-mIbnCSXXHmrs,2724
|
|
11
|
+
caraer_cli/resolve.py,sha256=fNMZ-DfKquVAwQ4jtqfDYcGFgOtIr1y7On1EjarfTbQ,1896
|
|
12
|
+
caraer_cli/utils.py,sha256=9vH4qrlZfEBQt-8v2Jxk36D4FB6ivFWpdKWRfi38YeE,1116
|
|
13
|
+
caraer_cli/api/__init__.py,sha256=60wi9mbwxCr1BLHYZIsTowkm8YSyVbncJcMn2lsCBLU,53
|
|
14
|
+
caraer_cli/api/apps.py,sha256=0AH1pl4QbJI44D-B-xAzhOFFuN8pkIrHOEuy44_qRIs,2196
|
|
15
|
+
caraer_cli/api/auth.py,sha256=VkGK9R_SgzRwqz8MQds-DB-yQix3AfG2sQla6BNGiS0,1551
|
|
16
|
+
caraer_cli/api/client.py,sha256=SulDeMj8CkCqBtp0HMvPfi7Pfvpzvdh7foZ3jPnIo_o,6706
|
|
17
|
+
caraer_cli/api/functions.py,sha256=-frlnAT1dfpcJ_YgMTMTLVSdXOx9ONesiqykIYdmbaA,2230
|
|
18
|
+
caraer_cli/api/installation.py,sha256=WslGiX3rdqw-M_FAVRmjs-TwlJoLNnhw-5KSFQaObVg,2919
|
|
19
|
+
caraer_cli/api/integration_runtime.py,sha256=cYfypwmIFnr-JKhMRHCL9NmFBKBKpxQasb3dlfe4a3Q,2771
|
|
20
|
+
caraer_cli/api/projects.py,sha256=aoKnfaXtqN1PdX2Yd6-Vf-fhwSc3YUVxQtvH67fxMcQ,6825
|
|
21
|
+
caraer_cli/api/sandboxes.py,sha256=4-FoQDPn5x6tFYWpj_OpZMZoBM5Y1-niVFLfSrHe-ks,814
|
|
22
|
+
caraer_cli/api/webhooks.py,sha256=-TEIseX9P-oFHDPV3e765PsrcSFoX6RL6WoTCuQshac,1943
|
|
23
|
+
caraer_cli/commands/__init__.py,sha256=IwxDewnPAA4_UwSd0VrJv6dcKYrJnGCbQKZnXAGU31Y,29
|
|
24
|
+
caraer_cli/commands/apps.py,sha256=8pGDhqlofCwOaMNI_v5uU_SkJFPykCTbuZ_PTJ2951M,76438
|
|
25
|
+
caraer_cli/commands/auth.py,sha256=-3asb5giCA0cEFyBAlRuBySf5QKpPq4ndWhYx4JNGT0,6460
|
|
26
|
+
caraer_cli/commands/company.py,sha256=RK8AQLkICQakF6PSKMfKB062YuFlJ_oTsNuZzHESYuo,2297
|
|
27
|
+
caraer_cli/commands/installation.py,sha256=_ym0zb0KxuIVsd6VRMw1dk8AQ6MJb8a6IScoUMIyHFg,6647
|
|
28
|
+
caraer_cli/commands/profile.py,sha256=9ewROdS2FaL1vLgpHVZNWMzAsfvvaxlz-9Fki7nog2U,8421
|
|
29
|
+
caraer_cli/commands/publish.py,sha256=ogpE20rH0mlpoBwJQmbzatHFhbgmx489-C4K4bTKKVY,1598
|
|
30
|
+
caraer_cli/commands/sandbox.py,sha256=6UuIlxI8vXE40DmKTIZWkjr2SyEKCgccgp2SJjYJxYg,3659
|
|
31
|
+
caraer_cli/commands/skill.py,sha256=XFBXuc91ph80HQK5PAxaLHDVG5hW3UzpKIP4spIr-RY,4914
|
|
32
|
+
caraer_cli/commands/webhooks.py,sha256=O3DE6B-2xq0Y7322OlJ6KovpNfzTdJB70zk0yYnr7I8,2380
|
|
33
|
+
caraer_cli/formatters/__init__.py,sha256=56IfCskco_Sm5aJbo3KII0R_OB1Ah1rkCH-0g1Yn94Q,33
|
|
34
|
+
caraer_cli/formatters/output.py,sha256=h6gkzX0WdeexVvuq34-hsAZsTJmoSvU48SVHrHiEaaE,12021
|
|
35
|
+
caraer_cli/formatters/timestamps.py,sha256=B2jxKrK5rMJT_O8zvTCZ_h1uGwvBRQDeiaej9ZXFLIs,3353
|
|
36
|
+
caraer_cli/models/__init__.py,sha256=wfNKpsbQJIPeAPB8Km-VNSMwmmYW2a5CnSq0GmTh61M,41
|
|
37
|
+
caraer_cli/models/api.py,sha256=X69NgY7JVbMCjYiIb0P2qfQxloibrUb75I6jISdI8HM,1161
|
|
38
|
+
caraer_cli/project/__init__.py,sha256=h08REXIjim71wcdOii_4Fb2LL-1e-5QnYUex-GC7GF4,340
|
|
39
|
+
caraer_cli/project/app_bars_sync.py,sha256=THrY-OSLy6DComkXS-MMkKmxnKQo4USMEZ-MCzV28e8,4524
|
|
40
|
+
caraer_cli/project/app_manifest_template.py,sha256=xfmBDHgzviUZe3jK7n_9QwDD10smbaDJLQAiL-Mhyfg,2328
|
|
41
|
+
caraer_cli/project/inbound_sync.py,sha256=x-XmMQ_CGsuJQ6Y5r3gowdtZXTAz4Sv5yMPBYerdog0,6839
|
|
42
|
+
caraer_cli/project/json_schemas.py,sha256=GYyqPbpfPSsvTr_FB5y5r_7mYbHJVMTNd2cGfqb9ZA0,2172
|
|
43
|
+
caraer_cli/project/lifecycle_sync.py,sha256=lktrihmW1a9gLxyXo1V1qZEbNHhWd3bzNTGTUZF-34Y,3715
|
|
44
|
+
caraer_cli/project/local_dev.py,sha256=ajBsNAqYpa78X0P_71bJcrQmGESnE-CKHmCxqI7-RT4,30419
|
|
45
|
+
caraer_cli/project/manifest_edit.py,sha256=dvI-1NLQVMeIDQKDvk1MuGXBtZT4NxHd1HSwVgZYswo,1720
|
|
46
|
+
caraer_cli/project/marketplace_assemble.py,sha256=7rj0wt_ZnA0SGL1fvdUSmJs4eGAB9yyHHAcfMcq4TKY,5533
|
|
47
|
+
caraer_cli/project/oauth_providers_sync.py,sha256=vVo3koIbfCPz6kZsSbirNYtEBIEI01PXjfF3Ryel_-U,6756
|
|
48
|
+
caraer_cli/project/paths.py,sha256=vAO0dYSBrdOEoNV_Q6Jo1Nyvfqm36T_mL0dqBOCOVCg,2889
|
|
49
|
+
caraer_cli/project/pricing_sync.py,sha256=9DMgA8GxGQO_5sQ0raeKOyHLEud6UXAzDD5m5q6udbY,2266
|
|
50
|
+
caraer_cli/project/push_plan.py,sha256=qmOWZ8hlImbVNxhNHATOQCBv1sQuu3xmoaUoYrncaak,20076
|
|
51
|
+
caraer_cli/project/release.py,sha256=X2r8qIToRZEjdJL6yJ7ZeO5B0-DvTjrqgbaOtHfrE54,4101
|
|
52
|
+
caraer_cli/project/scaffold.py,sha256=VfBP0pK7l5xRMKAE6NeMwbyeDiftB6i0zaz9AJgB7gM,18309
|
|
53
|
+
caraer_cli/project/schedules_sync.py,sha256=T3MYN82JhotD15BeojcagdTR6IGoZQ1PGZ5Q2EOEWR8,5858
|
|
54
|
+
caraer_cli/project/schema.py,sha256=zP1bAXKwE-5p1N5hsm_wQeCORS0DcQutksGCQMGoEBo,5410
|
|
55
|
+
caraer_cli/project/settings_sync.py,sha256=2LT96GZcoX3UnQMCEn4ZowdcuB0U8AjlEQ2CxjJ0PZ8,2096
|
|
56
|
+
caraer_cli/project/state.py,sha256=ZPVWghWPRBSVp4JG1ZzuwZEkBi0MkF-no9fUgwjOYHo,1394
|
|
57
|
+
caraer_cli/project/sync.py,sha256=84J0mdcXB2aPY3mn7HOjSPv-hGVhAe2vCv-Fkrcby9E,12598
|
|
58
|
+
caraer_cli/project/typegen.py,sha256=HbEogRvhMLM3sf92QunzihXv70959U9nrAOYuVMvzoc,6864
|
|
59
|
+
caraer_cli/project/validate_app.py,sha256=ob1ZF0_CkSqPzZXMqeSsuOUMf8cFNxl1kvsoPjTMhmM,40347
|
|
60
|
+
caraer_cli/project/webhooks_sync.py,sha256=9E-Lk9GVIWJmzSDdu2zgTkdJLfjS0HJ3-yS_Q395yqo,8299
|
|
61
|
+
caraer_cli/skills/.gitkeep,sha256=aFkniq_-kmZHPriRGXpvF7VdgajYJEcAUMVHFuKiyhE,155
|
|
62
|
+
caraer_cli/state/__init__.py,sha256=VS_pHleWqhNLnP1C9lniRY5D4Keq0i_SnYcHSavMN00,41
|
|
63
|
+
caraer_cli/state/config.py,sha256=Uu4xEzuWmW_imgWkMkxKEcTlPeiAjWcYsIDCmSiW8G8,4625
|
|
64
|
+
caraer_cli/state/session.py,sha256=2iDLR74tobUHcBFqBs_d-5CV3x-ZTFnINLkzYb5CAg8,2577
|
|
65
|
+
caraer_cli/wizard/__init__.py,sha256=khs1Kyk1VEREy6ortb8Jq3bgXAdDSJtOoJsgax-ocBA,223
|
|
66
|
+
caraer_cli/wizard/catalog.py,sha256=-oZ-ufkEMTtv4ewa1OwNfRSclKsxVRs8gK4zc9XL_Fc,4088
|
|
67
|
+
caraer_cli/wizard/marketplace.py,sha256=x271_omfScRwN4zrW3nzNuma8cEcL1XDegpYhtBevHc,11766
|
|
68
|
+
caraer_cli/wizard/prompts.py,sha256=yaTnOXrcqPWjAc2vz3G1U-SO5_CZx-hRUF1RzgxR3-s,2676
|
|
69
|
+
caraer_cli/wizard/public_app.py,sha256=NhUNjLg_QsJvojAPq5jf6Ha2IvsITAntcE1Ozn2jcbo,16462
|
|
70
|
+
caraer_cli/wizard/scope_macros.py,sha256=0RknbTx-jTL-Ff2V5MZbXv9i9oCwGHSUsTQRYR5ht3g,6638
|
|
71
|
+
caraer_cli/schemas/app.caraer.schema.json,sha256=-x5g7kb2VkxJ0AKCO1F4LOe1TSdb-PsZcAWIIAVNGII,5103
|
|
72
|
+
caraer_cli/schemas/function.caraer.schema.json,sha256=fvKzWtbMmD_zyX5p-r_pkWQnqhb94b3kypuqhyXQZaY,861
|
|
73
|
+
caraer_cli/schemas/inbound.caraer.schema.json,sha256=gsi4APeYpVeUSpZVAEfKWJ1A3y4cXkxFTFdfhwx4-G4,1413
|
|
74
|
+
caraer_cli/schemas/lifecycle.caraer.schema.json,sha256=OYXGlraLABrU7bk4aFW6IeRHt-Jyy52CA8AoQKvmNL8,1347
|
|
75
|
+
caraer_cli/schemas/schedule.caraer.schema.json,sha256=FDv7G3qeDLOeHL3aPuvJ-UC529bDt_DbLU_VINOy-Og,1085
|
|
76
|
+
caraer_cli/schemas/webhook.caraer.schema.json,sha256=6maZ2-ZWERFMfuDlJ9xnOOWy-tBo1MeC5PBwI47fmFo,1399
|
|
77
|
+
caraer_cli/skills/caraer-apps/SKILL.md,sha256=hGjype_sjeS-khWM3oz0grTIY4hLMN8s5zFj84TUP-0,5784
|
|
78
|
+
caraer_cli/skills/caraer-apps/reference.md,sha256=Orw-Yq9r3G5-BTbpdMVOEjEFITz2AgbQtu_ohema5-I,4109
|
|
79
|
+
caraer_cli-0.1.2.dist-info/METADATA,sha256=FahWRzMZQ2Z9Ou50XI9A3y9npS4YlzzfmBR6POMVhmY,9444
|
|
80
|
+
caraer_cli-0.1.2.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
81
|
+
caraer_cli-0.1.2.dist-info/entry_points.txt,sha256=DfHwHN2g08ODz4fjjpbS26KPMCSOuCoowGmSdKmCLfM,47
|
|
82
|
+
caraer_cli-0.1.2.dist-info/licenses/LICENSE,sha256=7mhXjqpbXZdIZgOzapCzwmuEg1rQJEiRoXZSOXXqSLg,422
|
|
83
|
+
caraer_cli-0.1.2.dist-info/RECORD,,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
Copyright (c) Caraer / Loyall. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and associated documentation files (the "Software") are proprietary
|
|
4
|
+
and confidential. Unauthorized copying, modification, distribution, or use of the
|
|
5
|
+
Software, in whole or in part, is strictly prohibited except as expressly permitted
|
|
6
|
+
in a written agreement with Caraer.
|
|
7
|
+
|
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|