@granular-software/sdk 0.4.13 → 0.4.14
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/README.md +14 -12
- package/dist/cli/index.js +362 -75
- package/dist/index.d.mts +95 -12
- package/dist/index.d.ts +95 -12
- package/dist/index.js +56 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -3440,7 +3440,7 @@ var require_main = __commonJS({
|
|
|
3440
3440
|
var os2 = __require("os");
|
|
3441
3441
|
var crypto = __require("crypto");
|
|
3442
3442
|
var packageJson = require_package();
|
|
3443
|
-
var
|
|
3443
|
+
var version2 = packageJson.version;
|
|
3444
3444
|
var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
|
|
3445
3445
|
function parse(src) {
|
|
3446
3446
|
const obj = {};
|
|
@@ -3489,13 +3489,13 @@ var require_main = __commonJS({
|
|
|
3489
3489
|
return DotenvModule.parse(decrypted);
|
|
3490
3490
|
}
|
|
3491
3491
|
function _warn(message) {
|
|
3492
|
-
console.log(`[dotenv@${
|
|
3492
|
+
console.log(`[dotenv@${version2}][WARN] ${message}`);
|
|
3493
3493
|
}
|
|
3494
3494
|
function _debug(message) {
|
|
3495
|
-
console.log(`[dotenv@${
|
|
3495
|
+
console.log(`[dotenv@${version2}][DEBUG] ${message}`);
|
|
3496
3496
|
}
|
|
3497
3497
|
function _log(message) {
|
|
3498
|
-
console.log(`[dotenv@${
|
|
3498
|
+
console.log(`[dotenv@${version2}] ${message}`);
|
|
3499
3499
|
}
|
|
3500
3500
|
function _dotenvKey(options) {
|
|
3501
3501
|
if (options && options.DOTENV_KEY && options.DOTENV_KEY.length > 0) {
|
|
@@ -6530,7 +6530,8 @@ async function main() {
|
|
|
6530
6530
|
|
|
6531
6531
|
// Connect as one app user so the SDK can create an environment for the seed run.
|
|
6532
6532
|
const env = await granular.connect({
|
|
6533
|
-
|
|
6533
|
+
ontology: SANDBOX_ID,
|
|
6534
|
+
environment: 'dev',
|
|
6534
6535
|
userId: '${template.seedUser.userId}',
|
|
6535
6536
|
name: '${template.seedUser.name}',
|
|
6536
6537
|
email: '${template.seedUser.email}',
|
|
@@ -6866,15 +6867,72 @@ var ApiClient = class {
|
|
|
6866
6867
|
);
|
|
6867
6868
|
return result.items;
|
|
6868
6869
|
}
|
|
6870
|
+
async listVersions(sandboxId) {
|
|
6871
|
+
const result = await this.request(
|
|
6872
|
+
`/control/sandboxes/${sandboxId}/versions`
|
|
6873
|
+
);
|
|
6874
|
+
return result.items;
|
|
6875
|
+
}
|
|
6869
6876
|
async getBuild(buildId) {
|
|
6870
6877
|
return this.request(`/control/builds/${buildId}`);
|
|
6871
6878
|
}
|
|
6879
|
+
async getVersion(versionId) {
|
|
6880
|
+
return this.request(`/control/versions/${versionId}`);
|
|
6881
|
+
}
|
|
6872
6882
|
async triggerBuild(sandboxId, manifestId) {
|
|
6873
6883
|
return this.request(`/control/sandboxes/${sandboxId}/builds`, {
|
|
6874
6884
|
method: "POST",
|
|
6875
6885
|
body: JSON.stringify({ manifestId })
|
|
6876
6886
|
});
|
|
6877
6887
|
}
|
|
6888
|
+
async createVersion(sandboxId, manifestId) {
|
|
6889
|
+
return this.triggerBuild(sandboxId, manifestId);
|
|
6890
|
+
}
|
|
6891
|
+
async listTags(sandboxId) {
|
|
6892
|
+
const result = await this.request(
|
|
6893
|
+
`/control/sandboxes/${sandboxId}/tags`
|
|
6894
|
+
);
|
|
6895
|
+
return result.items.map((tag2) => ({
|
|
6896
|
+
...tag2,
|
|
6897
|
+
targetVersionId: tag2.targetVersionId ?? tag2.targetBuildId ?? null
|
|
6898
|
+
}));
|
|
6899
|
+
}
|
|
6900
|
+
async moveTag(tagId, targetBuildId) {
|
|
6901
|
+
const moved = await this.request(`/control/tags/${tagId}/move`, {
|
|
6902
|
+
method: "POST",
|
|
6903
|
+
body: JSON.stringify({ targetBuildId })
|
|
6904
|
+
});
|
|
6905
|
+
return {
|
|
6906
|
+
...moved,
|
|
6907
|
+
targetVersionId: moved.targetVersionId ?? moved.targetBuildId ?? null
|
|
6908
|
+
};
|
|
6909
|
+
}
|
|
6910
|
+
async moveVersionTag(tagId, targetVersionId) {
|
|
6911
|
+
return this.moveTag(tagId, targetVersionId);
|
|
6912
|
+
}
|
|
6913
|
+
async promoteToProd(buildId) {
|
|
6914
|
+
return this.request(`/control/builds/${buildId}/promote`, {
|
|
6915
|
+
method: "POST"
|
|
6916
|
+
});
|
|
6917
|
+
}
|
|
6918
|
+
async promoteVersionToProd(versionId) {
|
|
6919
|
+
return this.request(`/control/versions/${versionId}/promote`, {
|
|
6920
|
+
method: "POST"
|
|
6921
|
+
});
|
|
6922
|
+
}
|
|
6923
|
+
async getBuildDiff(buildId, againstBuildId) {
|
|
6924
|
+
const query = againstBuildId ? `?against=${encodeURIComponent(againstBuildId)}` : "";
|
|
6925
|
+
return this.request(`/control/builds/${buildId}/diff${query}`);
|
|
6926
|
+
}
|
|
6927
|
+
async getVersionDiff(versionId, againstVersionId) {
|
|
6928
|
+
const query = againstVersionId ? `?against=${encodeURIComponent(againstVersionId)}` : "";
|
|
6929
|
+
const result = await this.request(`/control/versions/${versionId}/diff${query}`);
|
|
6930
|
+
return {
|
|
6931
|
+
versionId: result.buildId,
|
|
6932
|
+
againstVersionId: result.againstBuildId,
|
|
6933
|
+
diff: result.diff
|
|
6934
|
+
};
|
|
6935
|
+
}
|
|
6878
6936
|
async waitForBuild(buildId, onStatus, timeoutMs = 12e4) {
|
|
6879
6937
|
const start = Date.now();
|
|
6880
6938
|
while (Date.now() - start < timeoutMs) {
|
|
@@ -6891,6 +6949,9 @@ var ApiClient = class {
|
|
|
6891
6949
|
}
|
|
6892
6950
|
throw new Error(`Build timed out after ${Math.round(timeoutMs / 1e3)}s`);
|
|
6893
6951
|
}
|
|
6952
|
+
async waitForVersionBuild(versionId, onStatus, timeoutMs = 12e4) {
|
|
6953
|
+
return this.waitForBuild(versionId, onStatus, timeoutMs);
|
|
6954
|
+
}
|
|
6894
6955
|
// ── Permission Profiles ──
|
|
6895
6956
|
async createPermissionProfile(sandboxId, data) {
|
|
6896
6957
|
return this.request(
|
|
@@ -7542,10 +7603,10 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
7542
7603
|
return 3;
|
|
7543
7604
|
}
|
|
7544
7605
|
if ("TERM_PROGRAM" in env) {
|
|
7545
|
-
const
|
|
7606
|
+
const version2 = Number.parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
7546
7607
|
switch (env.TERM_PROGRAM) {
|
|
7547
7608
|
case "iTerm.app": {
|
|
7548
|
-
return
|
|
7609
|
+
return version2 >= 3 ? 3 : 2;
|
|
7549
7610
|
}
|
|
7550
7611
|
case "Apple_Terminal": {
|
|
7551
7612
|
return 2;
|
|
@@ -8595,7 +8656,7 @@ var brand = {
|
|
|
8595
8656
|
function printHeader() {
|
|
8596
8657
|
console.log();
|
|
8597
8658
|
console.log(brand.primary.bold(" \u25A0 Granular"));
|
|
8598
|
-
console.log(brand.muted("
|
|
8659
|
+
console.log(brand.muted(" Version and run ontologies from code"));
|
|
8599
8660
|
console.log();
|
|
8600
8661
|
}
|
|
8601
8662
|
function success(message) {
|
|
@@ -8777,10 +8838,11 @@ The rest of this guide assumes these terms.
|
|
|
8777
8838
|
| Term | What it means |
|
|
8778
8839
|
|------|----------------|
|
|
8779
8840
|
| **Sandbox** | A **workspace** on Granular (\`sbx_\u2026\`). It stores the **compiled domain** and **your records** for one project/environment. Not a browser sandbox \u2014 think \u201Ctenant + schema + data\u201D for this app. |
|
|
8780
|
-
| **Domain** | The **ontology**: **classes**, **relationships**, and **effects**. Declared in \`granular.json\`, installed on the sandbox by **
|
|
8781
|
-
| **Manifest** | \`granular.json\` (definition under \`manifest\`). **Source** in the repo until you **
|
|
8782
|
-
| **
|
|
8783
|
-
| **
|
|
8841
|
+
| **Domain** | The **ontology**: **classes**, **relationships**, and **effects**. Declared in \`granular.json\`, installed on the sandbox by creating a **version**. Same idea as *schema* / *model*. |
|
|
8842
|
+
| **Manifest** | \`granular.json\` (definition under \`manifest\`). **Source** in the repo until you create a new ontology **version** from it. |
|
|
8843
|
+
| **Version** | Immutable ontology state derived from one manifest revision. Tags like \`dev\` and \`prod\` point to versions. |
|
|
8844
|
+
| **Build run** | The CI-style compilation process. \`granular build\` creates or reuses the ontology version, then runs a build for it. |
|
|
8845
|
+
| **Environment** | Return value of \`granular.connect({ ontology, environment, \u2026 })\`. It is your **server-side** handle for \`recordObject\`, \`submitJob\`, \`graphql\`, etc., bound to one ontology environment slot. |
|
|
8784
8846
|
| **Session** | SDK base type; \`Environment\` **extends** \`Session\`. Job/prompt APIs live on \`Session\`; you still use the **\`Environment\`** instance from \`connect()\` in normal apps. |
|
|
8785
8847
|
| **Job** | Code string passed to \`environment.submitJob(code)\`. Runs in Granular\u2019s **sandbox runtime** with access to \`./sandbox-tools\` (generated classes + effect entrypoints). |
|
|
8786
8848
|
| **Effect** | Declared with \`withEffect\`; **handler** registered with \`registerEffects\` in **your** process. Jobs invoke effects; handlers do IO outside Granular. |
|
|
@@ -8801,9 +8863,9 @@ function manifestGuideEndToEndSection() {
|
|
|
8801
8863
|
| Step | Action | Outcome |
|
|
8802
8864
|
|------|--------|---------|
|
|
8803
8865
|
| 1 | Edit \`granular.json\` (\`manifest\` \u2192 \`volumes\` \u2192 \`operations\`) | Domain **source** in the repo |
|
|
8804
|
-
| 2 | \`granular build\` | Manifest **uploaded**;
|
|
8866
|
+
| 2 | \`granular build\` | Manifest **uploaded**; ontology version created or reused; build run compiles it; errors surface here |
|
|
8805
8867
|
| 3 | (Optional) Run your **effects host** \u2014 e.g. \`npx tsx granular-effects.ts\` \u2014 calling \`registerEffects(sandboxId, \u2026)\` | Effect **handlers** attached in **your** process |
|
|
8806
|
-
| 4 | \`new Granular({ apiKey })\` then \`connect({
|
|
8868
|
+
| 4 | \`new Granular({ apiKey })\` then \`connect({ ontology, environment, userId, permissions })\` | **\`Environment\`** for that ontology environment slot |
|
|
8807
8869
|
| 5 | \`recordObject\` / \`recordObjects\` | **Records** stored with correct fields and relationship keys |
|
|
8808
8870
|
| 6 | \`submitJob(\`\u2026\`)\` with imports from \`./sandbox-tools\` | **Jobs** run; may call **effects** \u2192 your handlers execute and return results |
|
|
8809
8871
|
|
|
@@ -8815,8 +8877,10 @@ function sandboxDocMainConceptsSection() {
|
|
|
8815
8877
|
| Term | One line |
|
|
8816
8878
|
|------|----------|
|
|
8817
8879
|
| **Sandbox** | Workspace \`sbx_\u2026\` \u2014 **domain** + **data** for this project. |
|
|
8818
|
-
| **Domain / ontology** | Classes + relationships + effects \u2014
|
|
8880
|
+
| **Domain / ontology** | Classes + relationships + effects \u2014 materialized from versioned manifests. |
|
|
8819
8881
|
| **Manifest** | \`granular.json\` \u2014 **source**; edit here, then \`granular build\`. |
|
|
8882
|
+
| **Version** | Immutable ontology state created from one manifest revision. |
|
|
8883
|
+
| **Build run** | Compilation run that validates and materializes a version. |
|
|
8820
8884
|
| **Environment** | \`connect()\` result \u2014 **record**, **submitJob**, **graphql** for this sandbox. |
|
|
8821
8885
|
| **Session** | Base type; \`Environment\` extends it (job APIs). |
|
|
8822
8886
|
| **Job** | \`submitJob\` code using \`./sandbox-tools\`. |
|
|
@@ -9103,7 +9167,7 @@ Example:
|
|
|
9103
9167
|
| \`isStatic\` | \`true\` \u2192 static method; \`false\` or omit \u2192 **instance** method (handler receives the object **id** first). |
|
|
9104
9168
|
| \`inputSchema\` / \`outputSchema\` | JSON Schema; used for codegen and validation. |
|
|
9105
9169
|
|
|
9106
|
-
**Lifecycle:** declare in manifest \u2192 \`granular build\` \u2192 implement handlers \u2192 \`granular.registerEffects(sandboxId, [...])\` \u2192 jobs call generated methods \u2192 your handler runs and returns the result to the job.
|
|
9170
|
+
**Lifecycle:** declare in manifest \u2192 \`granular build\` creates or reuses a version and runs the build \u2192 implement handlers \u2192 \`granular.registerEffects(sandboxId, [...])\` \u2192 jobs call generated methods \u2192 your handler runs and returns the result to the job.
|
|
9107
9171
|
|
|
9108
9172
|
**Permissions:** \`connect({ permissions: [...] })\` assigns profiles (e.g. \`default\`) that can allow or deny which effects a user may call.
|
|
9109
9173
|
|
|
@@ -9172,7 +9236,7 @@ ${effectMetamodelTable}
|
|
|
9172
9236
|
|-----|---------|
|
|
9173
9237
|
| \`new Granular({ apiKey, apiUrl?, endpointMode?, token?, tokenProvider?, \u2026 })\` | Auth. Env: \`GRANULAR_API_KEY\`, \`GRANULAR_API_URL\`, \`GRANULAR_ENDPOINT_MODE\`. |
|
|
9174
9238
|
| \`recordUser({ userId, name?, email?, permissions? })\` | Upsert user for later \`connect\`. |
|
|
9175
|
-
| \`connect({
|
|
9239
|
+
| \`connect({ ontology, environment, tagName?, userId?, granularId?, user?, permissions?, clientId?, initialHeap? })\` | Opens a session \u2192 **\`Environment\`**. \`tagName\` is an advanced override. |
|
|
9176
9240
|
| \`registerEffects(sandboxId, effects)\` / \`registerEffect\` | Register handlers for manifest \`withEffect\` declarations. |
|
|
9177
9241
|
| \`unregisterEffect\` / \`unregisterAllEffects\` / \`disconnectEffects\` | Stop effect handlers for a sandbox. |
|
|
9178
9242
|
| \`granular.sandboxes\` | \`.list()\`, \`.get\`, \`.create\`, \`.update\`, \`.delete\` |
|
|
@@ -9214,14 +9278,17 @@ Use \`environment.graphql(query, variables?)\` when you need **query/mutation ac
|
|
|
9214
9278
|
|
|
9215
9279
|
| Command | Purpose |
|
|
9216
9280
|
|---------|---------|
|
|
9217
|
-
| \`granular build\` | Upload \`granular.json
|
|
9218
|
-
| \`granular deploy\` |
|
|
9281
|
+
| \`granular build\` | Upload \`granular.json\`, create or reuse the matching ontology version, and run the build (**validation**). |
|
|
9282
|
+
| \`granular deploy\` | Push the current revision, build it, and update \`dev\`. |
|
|
9283
|
+
| \`granular deploy --prod\` | If the current version is already on \`dev\`, also point \`prod\` to it. Otherwise build it, then point both \`dev\` and \`prod\` to it. |
|
|
9284
|
+
| \`granular version diff\` | Show the semantic diff between ontology versions. |
|
|
9285
|
+
| \`granular tag move\` | Move \`dev\`, \`prod\`, or another tag to a chosen version. |
|
|
9219
9286
|
| \`granular dev\` | Watch manifest, rebuild on change. |
|
|
9220
9287
|
| \`granular document\` | Regenerate \`GRANULAR_SANDBOX.md\`. |
|
|
9221
9288
|
| \`granular init\` | Scaffold project; optional \`--agent-docs\`. |
|
|
9222
9289
|
| \`granular add class|field|relation\` | Mutate local manifest. |
|
|
9223
9290
|
| \`granular simulate\` | Open simulator in browser. |
|
|
9224
|
-
| \`granular pull
|
|
9291
|
+
| \`granular pull <version>\` | Pull the manifest for a specific ontology version. |
|
|
9225
9292
|
| \`granular login\`, \`granular whoami\`, \`granular status\` | Auth / project info. |
|
|
9226
9293
|
|
|
9227
9294
|
---
|
|
@@ -9230,7 +9297,7 @@ Use \`environment.graphql(query, variables?)\` when you need **query/mutation ac
|
|
|
9230
9297
|
|
|
9231
9298
|
1. \`granular build\` (or \`granular dev\`).
|
|
9232
9299
|
2. Align **effect handlers** with every \`withEffect\` name + schemas.
|
|
9233
|
-
3. \`granular document\` to refresh \`GRANULAR_SANDBOX.md\` without a full build if needed (build still
|
|
9300
|
+
3. \`granular document\` to refresh \`GRANULAR_SANDBOX.md\` without a full build if needed (the last successful version/build metadata still comes from \`granular build\` or \`granular deploy\`).
|
|
9234
9301
|
|
|
9235
9302
|
---
|
|
9236
9303
|
|
|
@@ -9315,9 +9382,9 @@ function generateSandboxAgentDoc(manifest, meta) {
|
|
|
9315
9382
|
lines.push(`| Sandbox id | \`${meta.sandboxId}\` |`);
|
|
9316
9383
|
if (meta.apiUrl) lines.push(`| API / WS base | \`${meta.apiUrl}\` |`);
|
|
9317
9384
|
if (meta.manifestId) lines.push(`| Last uploaded manifest id | \`${meta.manifestId}\` |`);
|
|
9318
|
-
if (meta.buildId) lines.push(`| Last
|
|
9385
|
+
if (meta.buildId) lines.push(`| Last version id | \`${meta.buildId}\` |`);
|
|
9319
9386
|
if (meta.buildPending) {
|
|
9320
|
-
lines.push("|
|
|
9387
|
+
lines.push("| Version status | *No successful version/build recorded in this doc run \u2014 run `granular build`.* |");
|
|
9321
9388
|
}
|
|
9322
9389
|
lines.push("");
|
|
9323
9390
|
lines.push("Set `GRANULAR_API_KEY` (e.g. in `.env.local`). Optional: `GRANULAR_API_URL` overrides the WebSocket URL.");
|
|
@@ -9334,7 +9401,9 @@ function generateSandboxAgentDoc(manifest, meta) {
|
|
|
9334
9401
|
lines.push("");
|
|
9335
9402
|
lines.push("| Command | Purpose |");
|
|
9336
9403
|
lines.push("|---------|---------|");
|
|
9337
|
-
lines.push("| `granular build` |
|
|
9404
|
+
lines.push("| `granular build` | Create or rebuild the current ontology version |");
|
|
9405
|
+
lines.push("| `granular version diff <version> [base]` | Show the semantic diff between versions |");
|
|
9406
|
+
lines.push("| `granular tag move <tag> <version>` | Move a release tag such as `prod` |");
|
|
9338
9407
|
lines.push("| `granular document` | Refresh this file from `granular.json` |");
|
|
9339
9408
|
lines.push("| `npx tsx " + seed + "` | Seed sample records (if present) |");
|
|
9340
9409
|
lines.push("| `npx tsx " + eff + "` | Run effect handler host (if present) |");
|
|
@@ -9350,7 +9419,8 @@ function generateSandboxAgentDoc(manifest, meta) {
|
|
|
9350
9419
|
lines.push(`});`);
|
|
9351
9420
|
lines.push("");
|
|
9352
9421
|
lines.push(`const env = await granular.connect({`);
|
|
9353
|
-
lines.push(`
|
|
9422
|
+
lines.push(` ontology: '${meta.sandboxId}',`);
|
|
9423
|
+
lines.push(` environment: 'dev',`);
|
|
9354
9424
|
lines.push(` userId: 'your_app_user_id',`);
|
|
9355
9425
|
lines.push(` permissions: ['default'],`);
|
|
9356
9426
|
lines.push(`});`);
|
|
@@ -9959,7 +10029,7 @@ async function loginCommand(options = {}) {
|
|
|
9959
10029
|
}
|
|
9960
10030
|
|
|
9961
10031
|
// src/cli/commands/pull.ts
|
|
9962
|
-
async function pullCommand() {
|
|
10032
|
+
async function pullCommand(versionId) {
|
|
9963
10033
|
printHeader();
|
|
9964
10034
|
const config = resolveConfig({ requireApiKey: true });
|
|
9965
10035
|
if (!config.sandboxId) {
|
|
@@ -9967,17 +10037,13 @@ async function pullCommand() {
|
|
|
9967
10037
|
process.exit(1);
|
|
9968
10038
|
}
|
|
9969
10039
|
const api = new ApiClient(config.apiKey, config.apiUrl);
|
|
9970
|
-
const spin = spinner(
|
|
10040
|
+
const spin = spinner(`Fetching version ${versionId}...`);
|
|
9971
10041
|
try {
|
|
9972
|
-
const
|
|
9973
|
-
|
|
9974
|
-
|
|
9975
|
-
hint("granular build", "Upload and build your local manifest");
|
|
9976
|
-
return;
|
|
9977
|
-
}
|
|
9978
|
-
const latest = manifests[0];
|
|
10042
|
+
const version2 = await api.getVersion(versionId);
|
|
10043
|
+
const targetManifestId = version2.manifestId;
|
|
10044
|
+
const targetVersionLabel = version2.versionNumber != null ? `v${version2.versionNumber}` : versionId;
|
|
9979
10045
|
spin.text = " Downloading manifest content...";
|
|
9980
|
-
const full = await api.getManifest(
|
|
10046
|
+
const full = await api.getManifest(targetManifestId);
|
|
9981
10047
|
if (!full.content) {
|
|
9982
10048
|
spin.fail(" Manifest has no content.");
|
|
9983
10049
|
return;
|
|
@@ -9989,8 +10055,9 @@ async function pullCommand() {
|
|
|
9989
10055
|
spin.succeed(" Manifest pulled successfully.");
|
|
9990
10056
|
console.log();
|
|
9991
10057
|
keyValue({
|
|
9992
|
-
"Manifest ID":
|
|
9993
|
-
"Version":
|
|
10058
|
+
"Manifest ID": full.manifestId,
|
|
10059
|
+
"Source Version": versionId,
|
|
10060
|
+
"Version": targetVersionLabel,
|
|
9994
10061
|
"Written to": "granular.json"
|
|
9995
10062
|
});
|
|
9996
10063
|
console.log();
|
|
@@ -10019,17 +10086,23 @@ async function buildCommand() {
|
|
|
10019
10086
|
uploading.fail(` Failed to upload manifest: ${err.message}`);
|
|
10020
10087
|
process.exit(1);
|
|
10021
10088
|
}
|
|
10022
|
-
const building = spinner("
|
|
10089
|
+
const building = spinner("Creating or reusing ontology version from manifest...");
|
|
10023
10090
|
try {
|
|
10024
|
-
const
|
|
10025
|
-
building.text = `
|
|
10091
|
+
const version2 = await api.createVersion(config.sandboxId, uploadedManifest.manifestId);
|
|
10092
|
+
building.text = ` Running build for version... ${brand.muted(version2.buildId)}`;
|
|
10026
10093
|
const startTime = Date.now();
|
|
10027
|
-
const completed = await api.
|
|
10094
|
+
const completed = await api.waitForVersionBuild(version2.buildId, (status) => {
|
|
10028
10095
|
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
10029
|
-
building.text = `
|
|
10096
|
+
building.text = ` Running build for version... ${brand.muted(`${status} (${elapsed}s)`)}`;
|
|
10030
10097
|
});
|
|
10031
10098
|
const totalTime = Math.round((Date.now() - startTime) / 1e3);
|
|
10032
|
-
building.succeed(`
|
|
10099
|
+
building.succeed(` Version ready in ${totalTime}s`);
|
|
10100
|
+
const [tags, diff] = await Promise.all([
|
|
10101
|
+
api.listTags(config.sandboxId),
|
|
10102
|
+
api.getVersionDiff(completed.buildId).catch(() => null)
|
|
10103
|
+
]);
|
|
10104
|
+
const devTag = tags.find((tag2) => tag2.name === "dev");
|
|
10105
|
+
const prodTag = tags.find((tag2) => tag2.name === "prod");
|
|
10033
10106
|
writeSandboxAgentDocFile(getProjectRoot(), manifest, {
|
|
10034
10107
|
sandboxId: config.sandboxId,
|
|
10035
10108
|
apiUrl: config.apiUrl,
|
|
@@ -10038,12 +10111,27 @@ async function buildCommand() {
|
|
|
10038
10111
|
});
|
|
10039
10112
|
console.log();
|
|
10040
10113
|
keyValue({
|
|
10041
|
-
"
|
|
10114
|
+
"Version ID": completed.buildId,
|
|
10115
|
+
"Version Number": completed.versionNumber != null ? String(completed.versionNumber) : "N/A",
|
|
10116
|
+
"Build Run": completed.buildRunId || completed.latestBuildRunId || "N/A",
|
|
10042
10117
|
"Manifest": uploadedManifest.manifestId,
|
|
10043
|
-
"
|
|
10118
|
+
"Result": completed.createdNewVersion ? "new version created" : "existing version reused, new build run recorded",
|
|
10119
|
+
"Dev Tag": devTag?.targetVersionId === completed.buildId || devTag?.targetBuildId === completed.buildId ? "updated to this version" : devTag?.targetVersionId || devTag?.targetBuildId || "not set",
|
|
10120
|
+
"Prod Tag": prodTag?.targetVersionId || prodTag?.targetBuildId || "not set",
|
|
10044
10121
|
"Duration": `${totalTime}s`,
|
|
10045
10122
|
"Agent doc": "GRANULAR_SANDBOX.md"
|
|
10046
10123
|
});
|
|
10124
|
+
if (diff?.diff?.summary) {
|
|
10125
|
+
console.log();
|
|
10126
|
+
keyValue({
|
|
10127
|
+
"Diff Added": String(diff.diff.summary.added ?? 0),
|
|
10128
|
+
"Diff Changed": String(diff.diff.summary.changed ?? 0),
|
|
10129
|
+
"Diff Removed": String(diff.diff.summary.removed ?? 0),
|
|
10130
|
+
"Transition Safety": diff.diff.summary.onlyAdditiveChanges ? "additive" : "breaking changes detected"
|
|
10131
|
+
});
|
|
10132
|
+
}
|
|
10133
|
+
console.log();
|
|
10134
|
+
info("Common path: keep working in your dev environment while dev follows the newest successful version. Prod only changes when you promote it.");
|
|
10047
10135
|
console.log();
|
|
10048
10136
|
} catch (err) {
|
|
10049
10137
|
building.fail(` Build failed: ${err.message}`);
|
|
@@ -10052,7 +10140,7 @@ async function buildCommand() {
|
|
|
10052
10140
|
}
|
|
10053
10141
|
|
|
10054
10142
|
// src/cli/commands/deploy.ts
|
|
10055
|
-
async function deployCommand() {
|
|
10143
|
+
async function deployCommand(options = {}) {
|
|
10056
10144
|
printHeader();
|
|
10057
10145
|
const config = resolveConfig({ requireApiKey: true, requireProject: true });
|
|
10058
10146
|
if (!config.sandboxId) {
|
|
@@ -10060,7 +10148,7 @@ async function deployCommand() {
|
|
|
10060
10148
|
process.exit(1);
|
|
10061
10149
|
}
|
|
10062
10150
|
const api = new ApiClient(config.apiKey, config.apiUrl);
|
|
10063
|
-
step("Deploy", `Sandbox ${config.sandboxId}`);
|
|
10151
|
+
step(options.prod ? "Deploy to dev and prod" : "Deploy to dev", `Sandbox ${config.sandboxId}`);
|
|
10064
10152
|
console.log();
|
|
10065
10153
|
const manifest = config.project.manifest;
|
|
10066
10154
|
const uploading = spinner(`Uploading manifest "${manifest.name}"...`);
|
|
@@ -10072,16 +10160,45 @@ async function deployCommand() {
|
|
|
10072
10160
|
uploading.fail(` Failed to upload manifest: ${err.message}`);
|
|
10073
10161
|
process.exit(1);
|
|
10074
10162
|
}
|
|
10075
|
-
const building = spinner("
|
|
10163
|
+
const building = spinner("Resolving ontology version from manifest...");
|
|
10076
10164
|
try {
|
|
10077
|
-
const
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
const
|
|
10084
|
-
|
|
10165
|
+
const [versions, tags] = await Promise.all([
|
|
10166
|
+
api.listVersions(config.sandboxId),
|
|
10167
|
+
api.listTags(config.sandboxId).catch(() => [])
|
|
10168
|
+
]);
|
|
10169
|
+
const devTag = tags.find((tag2) => tag2.name === "dev");
|
|
10170
|
+
const prodTag = tags.find((tag2) => tag2.name === "prod");
|
|
10171
|
+
const existingVersion = versions.find((version2) => version2.manifestDigest === uploadedManifest.digest) || null;
|
|
10172
|
+
const existingVersionId = existingVersion?.buildId || null;
|
|
10173
|
+
const devVersionId = devTag?.targetVersionId || devTag?.targetBuildId || null;
|
|
10174
|
+
const reuseDevPromotion = Boolean(
|
|
10175
|
+
options.prod && existingVersion && existingVersion.status === "completed" && existingVersionId && devVersionId === existingVersionId
|
|
10176
|
+
);
|
|
10177
|
+
let completed = existingVersion;
|
|
10178
|
+
let totalTime = 0;
|
|
10179
|
+
let deployedToDev = false;
|
|
10180
|
+
if (reuseDevPromotion) {
|
|
10181
|
+
building.succeed(` Current manifest already matches ${brand.secondary(existingVersionId)} on dev.`);
|
|
10182
|
+
} else {
|
|
10183
|
+
const version2 = await api.createVersion(config.sandboxId, uploadedManifest.manifestId);
|
|
10184
|
+
const startTime = Date.now();
|
|
10185
|
+
building.text = ` Running build for version... ${brand.muted(version2.buildId)}`;
|
|
10186
|
+
completed = await api.waitForVersionBuild(version2.buildId, (status) => {
|
|
10187
|
+
const elapsed = Math.round((Date.now() - startTime) / 1e3);
|
|
10188
|
+
building.text = ` Running build for version... ${brand.muted(`${status} (${elapsed}s)`)}`;
|
|
10189
|
+
});
|
|
10190
|
+
totalTime = Math.round((Date.now() - startTime) / 1e3);
|
|
10191
|
+
deployedToDev = true;
|
|
10192
|
+
building.succeed(` Dev now points to ${brand.secondary(completed.buildId)} (${totalTime}s)`);
|
|
10193
|
+
}
|
|
10194
|
+
if (!completed) {
|
|
10195
|
+
throw new Error("Could not resolve the current ontology version.");
|
|
10196
|
+
}
|
|
10197
|
+
if (options.prod) {
|
|
10198
|
+
const promoting = spinner("Promoting prod...");
|
|
10199
|
+
await api.promoteVersionToProd(completed.buildId);
|
|
10200
|
+
promoting.succeed(` Prod now points to ${brand.secondary(completed.buildId)}`);
|
|
10201
|
+
}
|
|
10085
10202
|
writeSandboxAgentDocFile(getProjectRoot(), manifest, {
|
|
10086
10203
|
sandboxId: config.sandboxId,
|
|
10087
10204
|
apiUrl: config.apiUrl,
|
|
@@ -10092,12 +10209,20 @@ async function deployCommand() {
|
|
|
10092
10209
|
success(`Deployed ${brand.bold(manifest.name)} successfully!`);
|
|
10093
10210
|
console.log();
|
|
10094
10211
|
keyValue({
|
|
10095
|
-
"
|
|
10212
|
+
"Version": completed.buildId,
|
|
10213
|
+
"Version Number": completed.versionNumber != null ? String(completed.versionNumber) : "N/A",
|
|
10214
|
+
"Build Run": completed.buildRunId || completed.latestBuildRunId || "N/A",
|
|
10096
10215
|
"Manifest": uploadedManifest.manifestId,
|
|
10097
|
-
"
|
|
10216
|
+
"Dev Tag": completed.buildId,
|
|
10217
|
+
"Prod Tag": options.prod ? completed.buildId : prodTag?.targetVersionId || prodTag?.targetBuildId || "unchanged",
|
|
10218
|
+
"Release": options.prod ? deployedToDev ? "dev and prod now point to this version" : "prod promoted to the version already on dev" : "dev updated to this version",
|
|
10098
10219
|
"Agent doc": "GRANULAR_SANDBOX.md"
|
|
10099
10220
|
});
|
|
10100
10221
|
console.log();
|
|
10222
|
+
if (options.prod) {
|
|
10223
|
+
info("Existing prod environments keep their current version until they are transitioned.");
|
|
10224
|
+
console.log();
|
|
10225
|
+
}
|
|
10101
10226
|
} catch (err) {
|
|
10102
10227
|
building.fail(` Deploy failed: ${err.message}`);
|
|
10103
10228
|
process.exit(1);
|
|
@@ -10125,21 +10250,30 @@ async function statusCommand() {
|
|
|
10125
10250
|
"Created": sandbox.createdAt
|
|
10126
10251
|
});
|
|
10127
10252
|
console.log();
|
|
10128
|
-
const builds = await api.
|
|
10253
|
+
const builds = await api.listVersions(config.sandboxId);
|
|
10254
|
+
const tags = await api.listTags(config.sandboxId).catch(() => []);
|
|
10255
|
+
const devTag = tags.find((tag2) => tag2.name === "dev");
|
|
10256
|
+
const prodTag = tags.find((tag2) => tag2.name === "prod");
|
|
10257
|
+
keyValue({
|
|
10258
|
+
"Dev Version": devTag?.targetVersionId || devTag?.targetBuildId || "not set",
|
|
10259
|
+
"Prod Version": prodTag?.targetVersionId || prodTag?.targetBuildId || "not set"
|
|
10260
|
+
});
|
|
10261
|
+
console.log();
|
|
10129
10262
|
if (builds.length > 0) {
|
|
10130
|
-
step("Recent
|
|
10263
|
+
step("Recent Versions");
|
|
10131
10264
|
console.log();
|
|
10132
10265
|
const recentBuilds = builds.slice(0, 5);
|
|
10133
10266
|
table(
|
|
10134
|
-
["
|
|
10267
|
+
["Version", "Status", "Users/Envs", "Created"],
|
|
10135
10268
|
recentBuilds.map((b) => [
|
|
10136
10269
|
b.buildId,
|
|
10137
10270
|
buildStatus(b.status),
|
|
10271
|
+
`${b.environmentCount ?? 0}/${b.sessionCount ?? 0}`,
|
|
10138
10272
|
b.createdAt ? String(b.createdAt) : "N/A"
|
|
10139
10273
|
])
|
|
10140
10274
|
);
|
|
10141
10275
|
} else {
|
|
10142
|
-
dim("No
|
|
10276
|
+
dim("No versions yet. Run `granular build` to create one.");
|
|
10143
10277
|
}
|
|
10144
10278
|
console.log();
|
|
10145
10279
|
const manifests = await api.listManifests(config.sandboxId);
|
|
@@ -10481,18 +10615,145 @@ async function simulateCommand(sandboxIdArg, options) {
|
|
|
10481
10615
|
openUrl(url);
|
|
10482
10616
|
}
|
|
10483
10617
|
|
|
10618
|
+
// src/cli/commands/version.ts
|
|
10619
|
+
function formatVersionLabel(versionId, versionNumber) {
|
|
10620
|
+
return versionNumber != null ? `v${versionNumber}` : versionId;
|
|
10621
|
+
}
|
|
10622
|
+
async function versionDiffCommand(versionId, againstVersionId) {
|
|
10623
|
+
printHeader();
|
|
10624
|
+
const config = resolveConfig({ requireApiKey: true });
|
|
10625
|
+
const api = new ApiClient(config.apiKey, config.apiUrl);
|
|
10626
|
+
const spin = spinner(
|
|
10627
|
+
againstVersionId ? `Computing diff ${versionId} \u2190 ${againstVersionId}...` : `Computing diff for ${versionId}...`
|
|
10628
|
+
);
|
|
10629
|
+
try {
|
|
10630
|
+
const [version2, diffResult] = await Promise.all([
|
|
10631
|
+
api.getVersion(versionId),
|
|
10632
|
+
api.getVersionDiff(versionId, againstVersionId)
|
|
10633
|
+
]);
|
|
10634
|
+
const baseVersion = diffResult.againstVersionId ? await api.getVersion(diffResult.againstVersionId).catch(() => null) : null;
|
|
10635
|
+
const summary = diffResult.diff.summary;
|
|
10636
|
+
spin.succeed(" Version diff ready.");
|
|
10637
|
+
console.log();
|
|
10638
|
+
keyValue({
|
|
10639
|
+
"Version": formatVersionLabel(version2.buildId, version2.versionNumber),
|
|
10640
|
+
"Compared against": baseVersion ? formatVersionLabel(baseVersion.buildId, baseVersion.versionNumber) : diffResult.againstVersionId || "previous version",
|
|
10641
|
+
"Added operations": summary.added,
|
|
10642
|
+
"Changed operations": summary.changed,
|
|
10643
|
+
"Removed operations": summary.removed,
|
|
10644
|
+
"Transition safety": summary.onlyAdditiveChanges ? "additive only" : "breaking changes detected"
|
|
10645
|
+
});
|
|
10646
|
+
if (diffResult.diff.entries.length === 0) {
|
|
10647
|
+
console.log();
|
|
10648
|
+
info("No ontology changes between these versions.");
|
|
10649
|
+
console.log();
|
|
10650
|
+
return;
|
|
10651
|
+
}
|
|
10652
|
+
console.log();
|
|
10653
|
+
step("Semantic diff");
|
|
10654
|
+
console.log();
|
|
10655
|
+
table(
|
|
10656
|
+
["Change", "Kind", "Operation", "Safety"],
|
|
10657
|
+
diffResult.diff.entries.map((entry) => [
|
|
10658
|
+
entry.changeType,
|
|
10659
|
+
entry.kind,
|
|
10660
|
+
entry.label,
|
|
10661
|
+
entry.additive ? "safe-add" : "breaking"
|
|
10662
|
+
])
|
|
10663
|
+
);
|
|
10664
|
+
console.log();
|
|
10665
|
+
} catch (err) {
|
|
10666
|
+
spin.fail(` Failed to compute diff: ${err.message}`);
|
|
10667
|
+
process.exit(1);
|
|
10668
|
+
}
|
|
10669
|
+
}
|
|
10670
|
+
|
|
10671
|
+
// src/cli/commands/tag.ts
|
|
10672
|
+
function renderVersionTarget(versionId) {
|
|
10673
|
+
if (!versionId) return "not set";
|
|
10674
|
+
return versionId;
|
|
10675
|
+
}
|
|
10676
|
+
async function tagListCommand() {
|
|
10677
|
+
printHeader();
|
|
10678
|
+
const config = resolveConfig({ requireApiKey: true });
|
|
10679
|
+
if (!config.sandboxId) {
|
|
10680
|
+
error("No ontology configured. Run `granular init` first.");
|
|
10681
|
+
process.exit(1);
|
|
10682
|
+
}
|
|
10683
|
+
const api = new ApiClient(config.apiKey, config.apiUrl);
|
|
10684
|
+
const spin = spinner("Loading tags...");
|
|
10685
|
+
try {
|
|
10686
|
+
const tags = await api.listTags(config.sandboxId);
|
|
10687
|
+
spin.succeed(" Tags loaded.");
|
|
10688
|
+
console.log();
|
|
10689
|
+
if (tags.length === 0) {
|
|
10690
|
+
dim("No tags defined for this ontology yet.");
|
|
10691
|
+
console.log();
|
|
10692
|
+
return;
|
|
10693
|
+
}
|
|
10694
|
+
table(
|
|
10695
|
+
["Tag", "Target version", "Kind", "Protected"],
|
|
10696
|
+
tags.map((tag2) => [
|
|
10697
|
+
tag2.name,
|
|
10698
|
+
renderVersionTarget(tag2.targetVersionId || tag2.targetBuildId),
|
|
10699
|
+
tag2.kind,
|
|
10700
|
+
tag2.protected ? "yes" : "no"
|
|
10701
|
+
])
|
|
10702
|
+
);
|
|
10703
|
+
console.log();
|
|
10704
|
+
} catch (err) {
|
|
10705
|
+
spin.fail(` Failed to load tags: ${err.message}`);
|
|
10706
|
+
process.exit(1);
|
|
10707
|
+
}
|
|
10708
|
+
}
|
|
10709
|
+
async function tagMoveCommand(tagName, versionId) {
|
|
10710
|
+
printHeader();
|
|
10711
|
+
const config = resolveConfig({ requireApiKey: true });
|
|
10712
|
+
if (!config.sandboxId) {
|
|
10713
|
+
error("No ontology configured. Run `granular init` first.");
|
|
10714
|
+
process.exit(1);
|
|
10715
|
+
}
|
|
10716
|
+
const api = new ApiClient(config.apiKey, config.apiUrl);
|
|
10717
|
+
const spin = spinner(`Moving ${tagName} to version ${versionId}...`);
|
|
10718
|
+
try {
|
|
10719
|
+
const tags = await api.listTags(config.sandboxId);
|
|
10720
|
+
const tag2 = tags.find((candidate) => candidate.name === tagName);
|
|
10721
|
+
if (!tag2) {
|
|
10722
|
+
spin.fail(` Tag "${tagName}" was not found for this ontology.`);
|
|
10723
|
+
process.exit(1);
|
|
10724
|
+
}
|
|
10725
|
+
const previousVersionId = tag2.targetVersionId || tag2.targetBuildId || null;
|
|
10726
|
+
const moved = await api.moveVersionTag(tag2.tagId, versionId);
|
|
10727
|
+
spin.succeed(` ${tagName} now points to ${versionId}.`);
|
|
10728
|
+
console.log();
|
|
10729
|
+
keyValue({
|
|
10730
|
+
"Tag": moved.name,
|
|
10731
|
+
"Previous version": previousVersionId || "not set",
|
|
10732
|
+
"Current version": moved.targetVersionId || moved.targetBuildId || "not set",
|
|
10733
|
+
"Protected": moved.protected ? "yes" : "no"
|
|
10734
|
+
});
|
|
10735
|
+
console.log();
|
|
10736
|
+
if (moved.name === "prod") {
|
|
10737
|
+
info("Existing prod environments keep their current version until they are transitioned.");
|
|
10738
|
+
console.log();
|
|
10739
|
+
} else if (moved.name === "dev") {
|
|
10740
|
+
info("dev is usually automatic. You only need to move it manually for exceptional release workflows.");
|
|
10741
|
+
console.log();
|
|
10742
|
+
}
|
|
10743
|
+
} catch (err) {
|
|
10744
|
+
spin.fail(` Failed to move tag: ${err.message}`);
|
|
10745
|
+
process.exit(1);
|
|
10746
|
+
}
|
|
10747
|
+
}
|
|
10748
|
+
|
|
10484
10749
|
// src/cli/index.ts
|
|
10485
10750
|
var VERSION = "0.2.0";
|
|
10486
10751
|
var program2 = new Command();
|
|
10487
|
-
program2.name("granular").description("
|
|
10488
|
-
program2.option("--local", "Use local endpoints (localhost)").option("--
|
|
10752
|
+
program2.name("granular").description("Version and run Granular ontologies from code").version(VERSION, "-v, --version");
|
|
10753
|
+
program2.option("--local", "Use local endpoints (localhost)").option("--env <target>", "Endpoint target: local|production");
|
|
10489
10754
|
program2.hook("preAction", () => {
|
|
10490
10755
|
const opts = program2.opts();
|
|
10491
10756
|
const normalizedEnv = opts.env?.trim().toLowerCase();
|
|
10492
|
-
if (opts.local && opts.prod) {
|
|
10493
|
-
error("Cannot use --local and --prod at the same time.");
|
|
10494
|
-
process.exit(1);
|
|
10495
|
-
}
|
|
10496
10757
|
if (normalizedEnv && !["local", "production", "prod"].includes(normalizedEnv)) {
|
|
10497
10758
|
error('Invalid --env value. Use "local" or "production".');
|
|
10498
10759
|
process.exit(1);
|
|
@@ -10500,7 +10761,7 @@ program2.hook("preAction", () => {
|
|
|
10500
10761
|
let mode;
|
|
10501
10762
|
if (opts.local || normalizedEnv === "local") {
|
|
10502
10763
|
mode = "local";
|
|
10503
|
-
} else if (
|
|
10764
|
+
} else if (normalizedEnv === "production" || normalizedEnv === "prod") {
|
|
10504
10765
|
mode = "production";
|
|
10505
10766
|
}
|
|
10506
10767
|
if (mode) {
|
|
@@ -10535,15 +10796,15 @@ program2.command("login").description("Authenticate with Granular (browser by de
|
|
|
10535
10796
|
process.exit(1);
|
|
10536
10797
|
}
|
|
10537
10798
|
});
|
|
10538
|
-
program2.command("pull").description("Pull the
|
|
10799
|
+
program2.command("pull <version-id>").description("Pull the manifest for a specific ontology version").action(async (versionId) => {
|
|
10539
10800
|
try {
|
|
10540
|
-
await pullCommand();
|
|
10801
|
+
await pullCommand(versionId);
|
|
10541
10802
|
} catch (err) {
|
|
10542
10803
|
error(err.message);
|
|
10543
10804
|
process.exit(1);
|
|
10544
10805
|
}
|
|
10545
10806
|
});
|
|
10546
|
-
program2.command("build").description("
|
|
10807
|
+
program2.command("build").description("Create or reuse the ontology version for your current manifest, then run its build").action(async () => {
|
|
10547
10808
|
try {
|
|
10548
10809
|
await buildCommand();
|
|
10549
10810
|
} catch (err) {
|
|
@@ -10551,15 +10812,15 @@ program2.command("build").description("Upload manifest and trigger a build").act
|
|
|
10551
10812
|
process.exit(1);
|
|
10552
10813
|
}
|
|
10553
10814
|
});
|
|
10554
|
-
program2.command("deploy").description("
|
|
10815
|
+
program2.command("deploy").description("Push the current revision to dev; use --prod to move prod there too").option("--prod", "Also point prod to the current version").action(async (opts) => {
|
|
10555
10816
|
try {
|
|
10556
|
-
await deployCommand();
|
|
10817
|
+
await deployCommand({ prod: opts.prod });
|
|
10557
10818
|
} catch (err) {
|
|
10558
10819
|
error(err.message);
|
|
10559
10820
|
process.exit(1);
|
|
10560
10821
|
}
|
|
10561
10822
|
});
|
|
10562
|
-
program2.command("status").description("Show
|
|
10823
|
+
program2.command("status").description("Show ontology versions, dev/prod, and manifest status").action(async () => {
|
|
10563
10824
|
try {
|
|
10564
10825
|
await statusCommand();
|
|
10565
10826
|
} catch (err) {
|
|
@@ -10567,6 +10828,32 @@ program2.command("status").description("Show sandbox and build status").action(a
|
|
|
10567
10828
|
process.exit(1);
|
|
10568
10829
|
}
|
|
10569
10830
|
});
|
|
10831
|
+
var version = program2.command("version").description("Inspect ontology versions");
|
|
10832
|
+
version.command("diff <version-id> [against-version-id]").description("Show the semantic diff between one version and another").action(async (versionId, againstVersionId) => {
|
|
10833
|
+
try {
|
|
10834
|
+
await versionDiffCommand(versionId, againstVersionId);
|
|
10835
|
+
} catch (err) {
|
|
10836
|
+
error(err.message);
|
|
10837
|
+
process.exit(1);
|
|
10838
|
+
}
|
|
10839
|
+
});
|
|
10840
|
+
var tag = program2.command("tag").description("Inspect and move release tags such as dev and prod");
|
|
10841
|
+
tag.command("list").description("List tags for the current ontology").action(async () => {
|
|
10842
|
+
try {
|
|
10843
|
+
await tagListCommand();
|
|
10844
|
+
} catch (err) {
|
|
10845
|
+
error(err.message);
|
|
10846
|
+
process.exit(1);
|
|
10847
|
+
}
|
|
10848
|
+
});
|
|
10849
|
+
tag.command("move <tag-name> <version-id>").description("Move a tag to a specific ontology version").action(async (tagName, versionId) => {
|
|
10850
|
+
try {
|
|
10851
|
+
await tagMoveCommand(tagName, versionId);
|
|
10852
|
+
} catch (err) {
|
|
10853
|
+
error(err.message);
|
|
10854
|
+
process.exit(1);
|
|
10855
|
+
}
|
|
10856
|
+
});
|
|
10570
10857
|
var add = program2.command("add").description("Add schema elements to the local manifest");
|
|
10571
10858
|
add.command("class <name>").description("Add a new class to the schema").action(async (name) => {
|
|
10572
10859
|
try {
|