@loxtep/sdk 0.8.0 → 0.9.0

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 (104) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +2 -1
  3. package/dist/cli/commands/clone-cmd.d.ts +39 -0
  4. package/dist/cli/commands/clone-cmd.d.ts.map +1 -0
  5. package/dist/cli/commands/clone-cmd.js +291 -0
  6. package/dist/cli/commands/clone-cmd.js.map +1 -0
  7. package/dist/cli/commands/deploy-cmd.d.ts.map +1 -1
  8. package/dist/cli/commands/deploy-cmd.js +51 -19
  9. package/dist/cli/commands/deploy-cmd.js.map +1 -1
  10. package/dist/cli/commands/init-cmd.d.ts.map +1 -1
  11. package/dist/cli/commands/init-cmd.js +12 -1
  12. package/dist/cli/commands/init-cmd.js.map +1 -1
  13. package/dist/cli/commands/link-cmd.d.ts +33 -0
  14. package/dist/cli/commands/link-cmd.d.ts.map +1 -0
  15. package/dist/cli/commands/link-cmd.js +145 -0
  16. package/dist/cli/commands/link-cmd.js.map +1 -0
  17. package/dist/cli/commands/projects-cmd.d.ts +39 -1
  18. package/dist/cli/commands/projects-cmd.d.ts.map +1 -1
  19. package/dist/cli/commands/projects-cmd.js +231 -4
  20. package/dist/cli/commands/projects-cmd.js.map +1 -1
  21. package/dist/cli/commands/projects-github-cmd.d.ts +24 -0
  22. package/dist/cli/commands/projects-github-cmd.d.ts.map +1 -0
  23. package/dist/cli/commands/projects-github-cmd.js +108 -0
  24. package/dist/cli/commands/projects-github-cmd.js.map +1 -0
  25. package/dist/cli/commands/push-cmd.d.ts +3 -7
  26. package/dist/cli/commands/push-cmd.d.ts.map +1 -1
  27. package/dist/cli/commands/push-cmd.js +10 -39
  28. package/dist/cli/commands/push-cmd.js.map +1 -1
  29. package/dist/cli/commands/status-cmd.d.ts +21 -0
  30. package/dist/cli/commands/status-cmd.d.ts.map +1 -0
  31. package/dist/cli/commands/status-cmd.js +127 -0
  32. package/dist/cli/commands/status-cmd.js.map +1 -0
  33. package/dist/cli/help.d.ts.map +1 -1
  34. package/dist/cli/help.js +17 -3
  35. package/dist/cli/help.js.map +1 -1
  36. package/dist/cli/index.js +62 -3
  37. package/dist/cli/index.js.map +1 -1
  38. package/dist/cli/known-locals-registry.d.ts +51 -0
  39. package/dist/cli/known-locals-registry.d.ts.map +1 -0
  40. package/dist/cli/known-locals-registry.js +94 -0
  41. package/dist/cli/known-locals-registry.js.map +1 -0
  42. package/dist/cli/project-context.d.ts +9 -0
  43. package/dist/cli/project-context.d.ts.map +1 -1
  44. package/dist/cli/project-context.js +21 -0
  45. package/dist/cli/project-context.js.map +1 -1
  46. package/dist/client/deployments-types.d.ts +40 -0
  47. package/dist/client/deployments-types.d.ts.map +1 -0
  48. package/dist/client/deployments-types.js +6 -0
  49. package/dist/client/deployments-types.js.map +1 -0
  50. package/dist/client/deployments.d.ts +13 -0
  51. package/dist/client/deployments.d.ts.map +1 -0
  52. package/dist/client/deployments.js +48 -0
  53. package/dist/client/deployments.js.map +1 -0
  54. package/dist/client/index.d.ts +10 -0
  55. package/dist/client/index.d.ts.map +1 -1
  56. package/dist/client/index.js +6 -0
  57. package/dist/client/index.js.map +1 -1
  58. package/dist/client/loxtep-client.d.ts.map +1 -1
  59. package/dist/client/loxtep-client.js +7 -1
  60. package/dist/client/loxtep-client.js.map +1 -1
  61. package/dist/client/project-workspace-inventory.d.ts +61 -0
  62. package/dist/client/project-workspace-inventory.d.ts.map +1 -0
  63. package/dist/client/project-workspace-inventory.js +300 -0
  64. package/dist/client/project-workspace-inventory.js.map +1 -0
  65. package/dist/client/project-workspace-status-types.d.ts +644 -0
  66. package/dist/client/project-workspace-status-types.d.ts.map +1 -0
  67. package/dist/client/project-workspace-status-types.js +265 -0
  68. package/dist/client/project-workspace-status-types.js.map +1 -0
  69. package/dist/client/project-workspace-status.d.ts +76 -0
  70. package/dist/client/project-workspace-status.d.ts.map +1 -0
  71. package/dist/client/project-workspace-status.js +368 -0
  72. package/dist/client/project-workspace-status.js.map +1 -0
  73. package/dist/client/projects.d.ts +53 -0
  74. package/dist/client/projects.d.ts.map +1 -1
  75. package/dist/client/projects.js +18 -0
  76. package/dist/client/projects.js.map +1 -1
  77. package/dist/client/versions-types.d.ts +3 -4
  78. package/dist/client/versions-types.d.ts.map +1 -1
  79. package/dist/client/versions-types.js +3 -4
  80. package/dist/client/versions-types.js.map +1 -1
  81. package/dist/client/workflows-types.d.ts +16 -3
  82. package/dist/client/workflows-types.d.ts.map +1 -1
  83. package/dist/client/workflows-types.js +47 -1
  84. package/dist/client/workflows-types.js.map +1 -1
  85. package/dist/client/workflows.d.ts.map +1 -1
  86. package/dist/client/workflows.js +2 -1
  87. package/dist/client/workflows.js.map +1 -1
  88. package/dist/client/workspace-package.d.ts +26 -0
  89. package/dist/client/workspace-package.d.ts.map +1 -0
  90. package/dist/client/workspace-package.js +85 -0
  91. package/dist/client/workspace-package.js.map +1 -0
  92. package/dist/client/workspace.d.ts +5 -1
  93. package/dist/client/workspace.d.ts.map +1 -1
  94. package/dist/client/workspace.js +3 -1
  95. package/dist/client/workspace.js.map +1 -1
  96. package/dist/config/platform-request-url.d.ts +2 -2
  97. package/dist/config/platform-request-url.js +4 -4
  98. package/docs/code-first-cli.md +28 -2
  99. package/docs/project-workspace-status.md +161 -0
  100. package/docs/sdk-mcp-mapping.md +1 -1
  101. package/package.json +1 -1
  102. package/schemas/entity-json-schemas/SCHEMA_SYNC.md +4 -3
  103. package/schemas/entity-json-schemas/data-product.json +1 -1
  104. package/schemas/entity-json-schemas/odps-product.json +1 -1
package/CHANGELOG.md CHANGED
@@ -6,6 +6,44 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to
7
7
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
8
 
9
+ ## [Unreleased]
10
+
11
+ ## [0.9.0] - 2026-08-07
12
+
13
+ ### Added
14
+
15
+ - **`loxtep projects clone` (LOX-1188)** — Cloud→Local project materialization
16
+ (GitHub clone when linked, or workspace export for unbound projects), plus
17
+ `projects pull` / `projects push` GitHub sync wrappers.
18
+ - **`loxtep link` / `projects link` (LOX-1186)** — bind a cloud project to a local
19
+ directory and track known locals in `~/.loxtep/workspaces.json`.
20
+ - **Unpublished inventory (LOX-1187)** — `loxtep status --unpublished` and
21
+ `loxtep projects changes` list Local→Cloud / Cloud→Deployed file+entity
22
+ deltas (workflows, connections, data products, schema package) using the same
23
+ discovery as `loxtep push`. Compares against `.loxtep/push-manifest.json`
24
+ (written on successful push); escalates with cloud workflow ids when linked.
25
+ `loxtep deploy` **warns** (does not block) when Local→Cloud is dirty.
26
+ - **`loxtep status`** — cwd-first project workspace status
27
+ (local attach + API host, GitHub linked|unbound, never-deployed / deployed /
28
+ stale, Local→Cloud and Cloud→Deployed dirty summaries, next-action hint).
29
+ Distinct from `loxtep observe status`. `--json` emits the full
30
+ `ProjectWorkspaceStatus` payload.
31
+ - **Enriched `loxtep projects list|get`** — cheap flags for github / local path
32
+ (when cwd matches) / deployed when detectable via deployments list.
33
+ - **Deployments list client** — `client.workspace.deployments.list` →
34
+ `GET /workflows/deployments`.
35
+ - **Project workspace status schema (LOX-1184)** — Zod + TypeScript types for
36
+ three-layer local / cloud / deployed status, unpublished deltas, list
37
+ enrichment, and population cost ceilings. Docs:
38
+ `docs/project-workspace-status.md`. Consumers: CLI `status` /
39
+ enriched `projects list|get`, MCP `get_project_workspace_status`
40
+ (planned).
41
+
42
+ ### Fixed
43
+
44
+ - **`loxtep deploy` tracking** — surfaces a real deployment / tracking id from
45
+ the deploy response instead of printing `undefined` for `run_id`.
46
+
9
47
  ## [0.8.0] - 2026-08-03
10
48
 
11
49
  ### Added
package/README.md CHANGED
@@ -337,6 +337,7 @@ await client.build.targets.delete('dp_abc123', webhook.consumption_id);
337
337
  | `init --create-repo [name]` | Scaffold + create a new GitHub repo (private default) |
338
338
  | `init --from-repo <url>` | Scaffold + import from an existing repo |
339
339
  | `attach --instance <name-or-id>` | Bind project to a runtime instance |
340
+ | `status [--json]` | Cwd-first workspace status (local/cloud/deployed; not observe) |
340
341
  | `connectors list [--type]` | List org connectors (filter e.g. `--type sdk`) |
341
342
  | `ingest provision [--name]` | Write local SDK ingest package (reuse/create connector; no deploy) |
342
343
  | `lint [--workflow]` | Validate local entity JSON (schemas + relationships) |
@@ -345,7 +346,7 @@ await client.build.targets.delete('dp_abc123', webhook.consumption_id);
345
346
  | `test <module> --event <file>` | Run a workflow module locally with sample event(s) |
346
347
  | `deploy` | Compile modules, validate resources, deploy to workflow engine |
347
348
  | `config list` | Show api_url, organization_id, project_id, instance_id |
348
- | `projects list` \| `projects get <id>` | List org projects (discover project_id) |
349
+ | `projects list` \| `projects get <id>` \| `projects link` \| `projects clone [dir]` \| `projects pull` \| `projects push` | List/get/link/clone; GH sync when bound; unbound Local→Cloud remains `loxtep push` |
349
350
  | `config paths` | Show resolved URLs for auth and SDK path matrix |
350
351
  | `config set <key> <value>` | Set api_url \| organization_id \| project_id \| instance_id |
351
352
  | `config export --from-data-product <id>` | Print shell exports / JSON for SDK bootstrap |
@@ -0,0 +1,39 @@
1
+ /**
2
+ * `loxtep projects clone <project_id|name> [dir]`
3
+ *
4
+ * Cloud → Local materialization (Railway-style “I have it in the cloud — get it here”).
5
+ *
6
+ * - **GitHub-bound:** `git clone` using `github_repo_url` (+ optional `github_repo_path`),
7
+ * then link-equivalent bind (`.loxtep/project.json` + known-locals).
8
+ * - **Unbound:** authenticated workspace export (`POST .../export`), write entity JSON
9
+ * files locally, then the same bind. Never pretends Git exists for unbound projects.
10
+ */
11
+ import type { LoxtepClient } from '../../client/loxtep-client.js';
12
+ import type { ProjectWorkspaceExportResult } from '../../client/projects.js';
13
+ import { type CliResult } from '../project-context.js';
14
+ export interface CloneOptions {
15
+ projectRef: string;
16
+ /** Destination directory (defaults to sanitized project name). */
17
+ dir?: string;
18
+ /** Optional registry path override (tests). */
19
+ registryPath?: string;
20
+ /**
21
+ * Test hooks — inject instead of real git / network for unit tests.
22
+ */
23
+ gitClone?: (args: {
24
+ url: string;
25
+ targetDir: string;
26
+ branch?: string;
27
+ }) => Promise<void>;
28
+ fetchExportJson?: (url: string) => Promise<ProjectWorkspaceExportResult['export_data']>;
29
+ }
30
+ /** Inject GH_TOKEN / GITHUB_TOKEN into https clone URLs when present. */
31
+ export declare function withGitHubAuth(cloneUrl: string): string;
32
+ /**
33
+ * Write exported entities as `<entity_type>/<entity_id>.json` under `targetDir`.
34
+ * Entity type strings already match Studio folder names (workflows, data-products, …).
35
+ */
36
+ export declare function materializeExportToDir(targetDir: string, exportData: NonNullable<ProjectWorkspaceExportResult['export_data']>): Promise<number>;
37
+ /** Core clone logic (testable without spawning the CLI process). */
38
+ export declare function runClone(client: LoxtepClient, options: CloneOptions): Promise<CliResult>;
39
+ //# sourceMappingURL=clone-cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clone-cmd.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/clone-cmd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAE7E,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,uBAAuB,CAAC;AAM/B,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,4BAA4B,CAAC,aAAa,CAAC,CAAC,CAAC;CACzF;AAcD,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAavD;AAkDD;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,WAAW,CAAC,4BAA4B,CAAC,aAAa,CAAC,CAAC,GACnE,OAAO,CAAC,MAAM,CAAC,CAajB;AAqMD,oEAAoE;AACpE,wBAAsB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,CAAC,CAgB9F"}
@@ -0,0 +1,291 @@
1
+ /**
2
+ * `loxtep projects clone <project_id|name> [dir]`
3
+ *
4
+ * Cloud → Local materialization (Railway-style “I have it in the cloud — get it here”).
5
+ *
6
+ * - **GitHub-bound:** `git clone` using `github_repo_url` (+ optional `github_repo_path`),
7
+ * then link-equivalent bind (`.loxtep/project.json` + known-locals).
8
+ * - **Unbound:** authenticated workspace export (`POST .../export`), write entity JSON
9
+ * files locally, then the same bind. Never pretends Git exists for unbound projects.
10
+ */
11
+ import { spawnSync } from 'node:child_process';
12
+ import { existsSync, mkdirSync } from 'node:fs';
13
+ import { mkdir, writeFile } from 'node:fs/promises';
14
+ import { basename, join, resolve } from 'node:path';
15
+ import { upsertKnownLocal } from '../known-locals-registry.js';
16
+ import { getProjectFilePath, PROJECT_DIR_NAME, PROJECT_FILE_NAME, writeProjectConfig, } from '../project-context.js';
17
+ import { buildLinkedProjectConfig, resolveCloudProject, } from './link-cmd.js';
18
+ function sanitizeDirName(name) {
19
+ const cleaned = name
20
+ .trim()
21
+ .replace(/[^a-zA-Z0-9._-]+/g, '-')
22
+ .replace(/^-+|-+$/g, '');
23
+ return cleaned || 'project';
24
+ }
25
+ function isGithubBound(cloud) {
26
+ return Boolean(cloud.github_repo_url && cloud.github_repo_url.trim());
27
+ }
28
+ /** Inject GH_TOKEN / GITHUB_TOKEN into https clone URLs when present. */
29
+ export function withGitHubAuth(cloneUrl) {
30
+ const token = (process.env.GH_TOKEN || process.env.GITHUB_TOKEN || '').trim();
31
+ if (!token)
32
+ return cloneUrl;
33
+ try {
34
+ const u = new URL(cloneUrl);
35
+ if (u.protocol !== 'https:')
36
+ return cloneUrl;
37
+ if (u.username || u.password)
38
+ return cloneUrl;
39
+ u.username = 'x-access-token';
40
+ u.password = token;
41
+ return u.toString();
42
+ }
43
+ catch {
44
+ return cloneUrl;
45
+ }
46
+ }
47
+ async function defaultGitClone(args) {
48
+ const authUrl = withGitHubAuth(args.url);
49
+ const cmd = ['clone', '--depth', '1'];
50
+ if (args.branch) {
51
+ cmd.push('--branch', args.branch);
52
+ }
53
+ cmd.push(authUrl, args.targetDir);
54
+ const res = spawnSync('git', cmd, {
55
+ encoding: 'utf-8',
56
+ env: process.env,
57
+ });
58
+ if (res.status !== 0) {
59
+ const err = (res.stderr || res.stdout || 'git clone failed').trim();
60
+ // Avoid leaking tokens in error paths if auth URL was rewritten
61
+ const scrubbed = err.replace(/x-access-token:[^@\s]+@/g, 'x-access-token:***@');
62
+ throw new Error(scrubbed || 'git clone failed');
63
+ }
64
+ }
65
+ async function defaultFetchExportJson(url) {
66
+ const res = await fetch(url);
67
+ if (!res.ok) {
68
+ throw new Error(`Failed to download export (${res.status} ${res.statusText})`);
69
+ }
70
+ const json = (await res.json());
71
+ if (json && typeof json === 'object' && 'entities' in json && Array.isArray(json.entities)) {
72
+ return json;
73
+ }
74
+ if (json &&
75
+ typeof json === 'object' &&
76
+ 'export_data' in json &&
77
+ json.export_data &&
78
+ Array.isArray(json.export_data.entities)) {
79
+ return json.export_data;
80
+ }
81
+ throw new Error('Export download did not contain entities[]');
82
+ }
83
+ /**
84
+ * Write exported entities as `<entity_type>/<entity_id>.json` under `targetDir`.
85
+ * Entity type strings already match Studio folder names (workflows, data-products, …).
86
+ */
87
+ export async function materializeExportToDir(targetDir, exportData) {
88
+ let written = 0;
89
+ for (const entity of exportData.entities ?? []) {
90
+ const type = String(entity.entity_type || '').replace(/^\/+|\/+$/g, '');
91
+ const id = String(entity.entity_id || '').replace(/[/\\]/g, '_');
92
+ if (!type || !id)
93
+ continue;
94
+ const dir = join(targetDir, type);
95
+ await mkdir(dir, { recursive: true });
96
+ const filePath = join(dir, `${id}.json`);
97
+ await writeFile(filePath, `${JSON.stringify(entity.data, null, 2)}\n`, 'utf-8');
98
+ written += 1;
99
+ }
100
+ return written;
101
+ }
102
+ async function bindLocalWorkspace(targetDir, cloud, registryPath) {
103
+ const config = buildLinkedProjectConfig(cloud);
104
+ // Prefer repository metadata from cloud when GH-bound so status enrichment can see it.
105
+ if (cloud.github_repo_url && cloud.github_repo_name) {
106
+ config.repository = {
107
+ url: cloud.github_repo_url,
108
+ name: cloud.github_repo_name,
109
+ branch: cloud.github_branch || 'main',
110
+ ...(cloud.github_repo_path ? { subpath: cloud.github_repo_path } : {}),
111
+ };
112
+ }
113
+ const projectFilePath = getProjectFilePath(targetDir);
114
+ await writeProjectConfig(projectFilePath, config);
115
+ await upsertKnownLocal({
116
+ path: targetDir,
117
+ project_id: cloud.project_id,
118
+ registryPath,
119
+ });
120
+ return { projectFilePath };
121
+ }
122
+ async function cloneGithubBound(client, cloud, targetDir, options) {
123
+ const url = cloud.github_repo_url.trim();
124
+ const branch = cloud.github_branch || undefined;
125
+ const gitClone = options.gitClone ?? defaultGitClone;
126
+ if (existsSync(targetDir)) {
127
+ return {
128
+ exitCode: 1,
129
+ stdout: [],
130
+ stderr: [`Clone failed: directory already exists: ${targetDir}`],
131
+ };
132
+ }
133
+ try {
134
+ await gitClone({ url, targetDir, branch });
135
+ }
136
+ catch (err) {
137
+ const reason = err instanceof Error ? err.message : String(err);
138
+ return {
139
+ exitCode: 1,
140
+ stdout: [],
141
+ stderr: [
142
+ `Clone failed (git): ${reason}`,
143
+ 'Tip: set GH_TOKEN or GITHUB_TOKEN for private HTTPS clones, or configure git credentials.',
144
+ ],
145
+ };
146
+ }
147
+ const subpath = (cloud.github_repo_path || '').replace(/^\/+|\/+$/g, '');
148
+ const workspaceRoot = subpath ? join(targetDir, subpath) : targetDir;
149
+ if (subpath && !existsSync(workspaceRoot)) {
150
+ return {
151
+ exitCode: 1,
152
+ stdout: [],
153
+ stderr: [
154
+ `Clone succeeded but github_repo_path "${subpath}" was not found under ${targetDir}.`,
155
+ ],
156
+ };
157
+ }
158
+ try {
159
+ await bindLocalWorkspace(workspaceRoot, cloud, options.registryPath);
160
+ }
161
+ catch (err) {
162
+ const reason = err instanceof Error ? err.message : String(err);
163
+ return {
164
+ exitCode: 1,
165
+ stdout: [],
166
+ stderr: [`Cloned repo but failed to write project bind: ${reason}`],
167
+ };
168
+ }
169
+ const lines = [
170
+ `Cloned GitHub-bound project "${cloud.name}" (${cloud.project_id})`,
171
+ ` git: ${url}${branch ? ` @ ${branch}` : ''}`,
172
+ ` workspace: ${workspaceRoot}`,
173
+ ` wrote ${PROJECT_DIR_NAME}/${PROJECT_FILE_NAME}`,
174
+ ` registered in ~/.loxtep/workspaces.json (known local)`,
175
+ '',
176
+ 'Next:',
177
+ ' cd ' + workspaceRoot,
178
+ ' loxtep status',
179
+ ' loxtep attach --instance <instance-id>',
180
+ ' loxtep projects pull # Cloud S3 ← GitHub (when bound)',
181
+ ' loxtep projects push # Cloud S3 → GitHub (when bound); unbound Local→Cloud uses `loxtep push`',
182
+ ];
183
+ return { exitCode: 0, stdout: lines, stderr: [] };
184
+ }
185
+ async function cloneUnboundExport(client, cloud, targetDir, options) {
186
+ if (existsSync(targetDir) && existsSync(getProjectFilePath(targetDir))) {
187
+ return {
188
+ exitCode: 1,
189
+ stdout: [],
190
+ stderr: [
191
+ `Clone failed: ${targetDir} already has ${PROJECT_DIR_NAME}/${PROJECT_FILE_NAME}.`,
192
+ 'Use `loxtep projects link` to rebind, or pick another directory.',
193
+ ],
194
+ };
195
+ }
196
+ mkdirSync(targetDir, { recursive: true });
197
+ let exported;
198
+ try {
199
+ exported = await client.workspace.projects.export_workspace(cloud.project_id, {
200
+ subscription_tier: 'enterprise',
201
+ validate_size: false,
202
+ include_drafts: false,
203
+ });
204
+ }
205
+ catch (err) {
206
+ const reason = err instanceof Error ? err.message : String(err);
207
+ return {
208
+ exitCode: 1,
209
+ stdout: [],
210
+ stderr: [
211
+ `Clone failed (workspace export): ${reason}`,
212
+ 'Unbound projects require POST /workflows/projects/{id}/export (deploy workflows MS if missing).',
213
+ ],
214
+ };
215
+ }
216
+ let exportData = exported.export_data;
217
+ if (!exportData && exported.presigned_url) {
218
+ const fetchJson = options.fetchExportJson ?? defaultFetchExportJson;
219
+ try {
220
+ exportData = await fetchJson(exported.presigned_url);
221
+ }
222
+ catch (err) {
223
+ const reason = err instanceof Error ? err.message : String(err);
224
+ return {
225
+ exitCode: 1,
226
+ stdout: [],
227
+ stderr: [`Clone failed downloading export artifact: ${reason}`],
228
+ };
229
+ }
230
+ }
231
+ if (!exportData?.entities) {
232
+ return {
233
+ exitCode: 1,
234
+ stdout: [],
235
+ stderr: ['Clone failed: export response had neither export_data nor a usable presigned_url.'],
236
+ };
237
+ }
238
+ let entityCount = 0;
239
+ try {
240
+ entityCount = await materializeExportToDir(targetDir, exportData);
241
+ }
242
+ catch (err) {
243
+ const reason = err instanceof Error ? err.message : String(err);
244
+ return { exitCode: 1, stdout: [], stderr: [`Clone failed writing entities: ${reason}`] };
245
+ }
246
+ try {
247
+ await bindLocalWorkspace(targetDir, cloud, options.registryPath);
248
+ }
249
+ catch (err) {
250
+ const reason = err instanceof Error ? err.message : String(err);
251
+ return {
252
+ exitCode: 1,
253
+ stdout: [],
254
+ stderr: [`Wrote ${entityCount} entities but failed to bind project config: ${reason}`],
255
+ };
256
+ }
257
+ const lines = [
258
+ `Cloned unbound project "${cloud.name}" (${cloud.project_id}) via workspace export`,
259
+ ` directory: ${targetDir}`,
260
+ ` entities: ${entityCount}`,
261
+ ` wrote ${PROJECT_DIR_NAME}/${PROJECT_FILE_NAME}`,
262
+ ` registered in ~/.loxtep/workspaces.json (known local)`,
263
+ '',
264
+ 'Next:',
265
+ ' cd ' + targetDir,
266
+ ' loxtep status',
267
+ ' loxtep attach --instance <instance-id>',
268
+ ' loxtep push # Local → Cloud (unbound package path; not Git)',
269
+ '',
270
+ 'Note: this project has no GitHub binding — do not use `projects pull/push` (those wrap GitHub sync APIs).',
271
+ ];
272
+ return { exitCode: 0, stdout: lines, stderr: [] };
273
+ }
274
+ /** Core clone logic (testable without spawning the CLI process). */
275
+ export async function runClone(client, options) {
276
+ let cloud;
277
+ try {
278
+ cloud = await resolveCloudProject(client, options.projectRef);
279
+ }
280
+ catch (err) {
281
+ const reason = err instanceof Error ? err.message : String(err);
282
+ return { exitCode: 1, stdout: [], stderr: [`Clone failed: ${reason}`] };
283
+ }
284
+ const defaultName = sanitizeDirName(cloud.name || basename(cloud.project_id));
285
+ const targetDir = resolve(options.dir ?? defaultName);
286
+ if (isGithubBound(cloud)) {
287
+ return cloneGithubBound(client, cloud, targetDir, options);
288
+ }
289
+ return cloneUnboundExport(client, cloud, targetDir, options);
290
+ }
291
+ //# sourceMappingURL=clone-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clone-cmd.js","sourceRoot":"","sources":["../../../src/cli/commands/clone-cmd.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-cmd.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/deploy-cmd.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deploy-cmd.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/deploy-cmd.ts"],"names":[],"mappings":"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"}
@@ -29,7 +29,31 @@ import { loadWorkspaceContext } from '../../codegen/load-workspace-context.js';
29
29
  import { normalizeContext } from '../../codegen/normalize.js';
30
30
  import { compileModule, computeRemovalSet } from '../../authoring/compiler.js';
31
31
  import { formatLintResult, runLintCheck } from './lint-cmd.js';
32
- import { listLocalWorkflowIds, collectFlatBundle } from './push-cmd.js';
32
+ import { listLocalWorkflowIds, collectFlatBundle } from '../../client/workspace-package.js';
33
+ import { buildLocalToCloudInventory } from '../../client/project-workspace-inventory.js';
34
+ function trackingHandleFromDeployResult(result) {
35
+ const run_id = result.run_id ?? result.deployment_id;
36
+ const status = result.status ?? result.message;
37
+ if (!run_id && !status) {
38
+ return undefined;
39
+ }
40
+ return {
41
+ run_id: run_id ?? '(none)',
42
+ status: status ?? 'unknown',
43
+ };
44
+ }
45
+ function formatTrackingLines(trackingHandle) {
46
+ const lines = [
47
+ `Deployment tracking: run_id=${trackingHandle.run_id}, status=${trackingHandle.status}`,
48
+ ];
49
+ if (trackingHandle.run_id !== 'unknown' && trackingHandle.run_id !== '(none)') {
50
+ lines.push('Deploy fan-out is async; check activity / the UI for completion. (CLI status poll TBD.)');
51
+ }
52
+ else if (trackingHandle.run_id === '(none)') {
53
+ lines.push('Platform returned deploy status without a run_id (backend contract outdated or still nested).');
54
+ }
55
+ return lines;
56
+ }
33
57
  // ────────────────────────────────────────────────────────────────────────────
34
58
  // Module loader
35
59
  // ────────────────────────────────────────────────────────────────────────────
@@ -107,7 +131,7 @@ export async function deployLocalEntityWorkflows(client, projectDir, projectId,
107
131
  project_id: projectId,
108
132
  instance_id: instanceId,
109
133
  });
110
- trackingHandle = { run_id: result.deployment_id, status: result.status };
134
+ trackingHandle = trackingHandleFromDeployResult(result);
111
135
  }
112
136
  catch (err) {
113
137
  const message = err instanceof Error ? err.message : String(err);
@@ -269,6 +293,19 @@ export async function runDeployCommand(options = {}) {
269
293
  }
270
294
  const { projectDir, project } = precondition;
271
295
  const { project_id: projectId, instance_id: instanceId } = project;
296
+ // Warn (do not block) when Local→Cloud is dirty — push first unless product adds --force.
297
+ const localToCloud = buildLocalToCloudInventory({ projectDir });
298
+ const dirtyWarnLines = [];
299
+ if (localToCloud.dirty === true) {
300
+ dirtyWarnLines.push(`Warning: Local→Cloud unpublished (${localToCloud.summary ?? 'dirty'}). Consider \`loxtep push\` before deploy.`);
301
+ const preview = (localToCloud.changes ?? []).slice(0, 8);
302
+ for (const c of preview) {
303
+ dirtyWarnLines.push(` [${c.change}] ${c.path}`);
304
+ }
305
+ if ((localToCloud.changes?.length ?? 0) > preview.length) {
306
+ dirtyWarnLines.push(` … and ${(localToCloud.changes?.length ?? 0) - preview.length} more (see \`loxtep status --unpublished\`)`);
307
+ }
308
+ }
272
309
  // 1b. Entity-package lint preflight (same engine as `loxtep lint`)
273
310
  const lint = runLintCheck({ cwd: projectDir });
274
311
  if (!lint.ok) {
@@ -276,6 +313,7 @@ export async function runDeployCommand(options = {}) {
276
313
  exitCode: 1,
277
314
  stdout: [],
278
315
  stderr: [
316
+ ...dirtyWarnLines,
279
317
  'Deploy refused: local entity package failed lint.',
280
318
  ...formatLintResult(lint),
281
319
  ],
@@ -288,7 +326,7 @@ export async function runDeployCommand(options = {}) {
288
326
  return {
289
327
  exitCode: 0,
290
328
  stdout: ['Deploy dry-run: lint only.', ...lintLines],
291
- stderr: [],
329
+ stderr: dirtyWarnLines,
292
330
  };
293
331
  }
294
332
  // 2. Get an authenticated client
@@ -318,7 +356,7 @@ export async function runDeployCommand(options = {}) {
318
356
  return {
319
357
  exitCode: 0,
320
358
  stdout: ['No workflow modules found in workflows/. Nothing to deploy.'],
321
- stderr: [],
359
+ stderr: dirtyWarnLines,
322
360
  };
323
361
  }
324
362
  const { pushed, trackingHandle } = await deployLocalEntityWorkflows(client, projectDir, projectId, instanceId);
@@ -333,20 +371,20 @@ export async function runDeployCommand(options = {}) {
333
371
  }
334
372
  if (trackingHandle) {
335
373
  outputLines.push('');
336
- outputLines.push(`Deployment tracking: run_id=${trackingHandle.run_id}, status=${trackingHandle.status}`);
337
- outputLines.push('Poll status with: loxtep workflows deploy --status <run_id>');
374
+ outputLines.push(...formatTrackingLines(trackingHandle));
338
375
  }
339
376
  if (failed.length > 0) {
340
377
  return {
341
378
  exitCode: 1,
342
379
  stdout: outputLines,
343
380
  stderr: [
381
+ ...dirtyWarnLines,
344
382
  'Some local workflow packages failed to push (previous versions remain running):',
345
383
  ...failed.map(p => ` ${p.workflow_id}: ${p.error}`),
346
384
  ],
347
385
  };
348
386
  }
349
- return { exitCode: 0, stdout: outputLines, stderr: [] };
387
+ return { exitCode: 0, stdout: outputLines, stderr: dirtyWarnLines };
350
388
  }
351
389
  // 5. Compile all modules (R1.11: collect compile errors with file:line)
352
390
  const compileErrors = [];
@@ -431,15 +469,12 @@ export async function runDeployCommand(options = {}) {
431
469
  project_id: projectId,
432
470
  instance_id: instanceId,
433
471
  });
434
- trackingHandle = {
435
- run_id: result.deployment_id,
436
- status: result.status,
437
- };
472
+ trackingHandle = trackingHandleFromDeployResult(result);
438
473
  // When deploying from S3 bundle, the platform handles all workflows atomically
439
474
  for (const { compiled } of compiledModules) {
440
475
  deployResults.push({
441
476
  name: compiled.name,
442
- workflow_id: compiled.workflow_id ?? result.deployment_id,
477
+ workflow_id: compiled.workflow_id ?? trackingHandle?.run_id ?? 'unknown',
443
478
  status: compiled.workflow_id ? 'updated' : 'created',
444
479
  });
445
480
  }
@@ -475,10 +510,7 @@ export async function runDeployCommand(options = {}) {
475
510
  project_id: projectId,
476
511
  instance_id: instanceId,
477
512
  });
478
- trackingHandle = {
479
- run_id: result.deployment_id,
480
- status: result.status,
481
- };
513
+ trackingHandle = trackingHandleFromDeployResult(result);
482
514
  }
483
515
  catch (err) {
484
516
  // Deploy orchestrator failure is non-fatal for the workflow creation/update,
@@ -540,8 +572,7 @@ export async function runDeployCommand(options = {}) {
540
572
  // Tracking handle (R18.5)
541
573
  if (trackingHandle) {
542
574
  outputLines.push('');
543
- outputLines.push(`Deployment tracking: run_id=${trackingHandle.run_id}, status=${trackingHandle.status}`);
544
- outputLines.push('Poll status with: loxtep workflows deploy --status <run_id>');
575
+ outputLines.push(...formatTrackingLines(trackingHandle));
545
576
  }
546
577
  // If there were failed deploys, report them but still exit 0 for partial success
547
578
  // (R3.6: the previously deployed version remains running)
@@ -551,6 +582,7 @@ export async function runDeployCommand(options = {}) {
551
582
  exitCode: 1,
552
583
  stdout: outputLines,
553
584
  stderr: [
585
+ ...dirtyWarnLines,
554
586
  'Some workflows failed to deploy (previous versions remain running):',
555
587
  ...stderrLines,
556
588
  ],
@@ -559,7 +591,7 @@ export async function runDeployCommand(options = {}) {
559
591
  return {
560
592
  exitCode: 0,
561
593
  stdout: outputLines,
562
- stderr: [],
594
+ stderr: dirtyWarnLines,
563
595
  };
564
596
  }
565
597
  /**