@inquir/compute-cli 0.2.2 → 0.4.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 (119) hide show
  1. package/README.md +228 -21
  2. package/dist/commands/admin-tenants.d.ts +11 -0
  3. package/dist/commands/admin-tenants.d.ts.map +1 -0
  4. package/dist/commands/admin-tenants.js +318 -0
  5. package/dist/commands/admin-tenants.js.map +1 -0
  6. package/dist/commands/admin.d.ts +2 -0
  7. package/dist/commands/admin.d.ts.map +1 -0
  8. package/dist/commands/admin.js +445 -0
  9. package/dist/commands/admin.js.map +1 -0
  10. package/dist/commands/apps-describe.d.ts +9 -0
  11. package/dist/commands/apps-describe.d.ts.map +1 -0
  12. package/dist/commands/apps-describe.js +118 -0
  13. package/dist/commands/apps-describe.js.map +1 -0
  14. package/dist/commands/apps-observability.d.ts +9 -0
  15. package/dist/commands/apps-observability.d.ts.map +1 -0
  16. package/dist/commands/apps-observability.js +281 -0
  17. package/dist/commands/apps-observability.js.map +1 -0
  18. package/dist/commands/apps-promote.d.ts +31 -0
  19. package/dist/commands/apps-promote.d.ts.map +1 -0
  20. package/dist/commands/apps-promote.js +115 -0
  21. package/dist/commands/apps-promote.js.map +1 -0
  22. package/dist/commands/apps-resources.d.ts +6 -0
  23. package/dist/commands/apps-resources.d.ts.map +1 -0
  24. package/dist/commands/apps-resources.js +107 -0
  25. package/dist/commands/apps-resources.js.map +1 -0
  26. package/dist/commands/apps.d.ts +65 -5
  27. package/dist/commands/apps.d.ts.map +1 -1
  28. package/dist/commands/apps.js +1293 -89
  29. package/dist/commands/apps.js.map +1 -1
  30. package/dist/commands/config.d.ts.map +1 -1
  31. package/dist/commands/config.js +7 -3
  32. package/dist/commands/config.js.map +1 -1
  33. package/dist/commands/delete.d.ts.map +1 -1
  34. package/dist/commands/delete.js +10 -2
  35. package/dist/commands/delete.js.map +1 -1
  36. package/dist/commands/deploy.d.ts +38 -0
  37. package/dist/commands/deploy.d.ts.map +1 -1
  38. package/dist/commands/deploy.js +165 -12
  39. package/dist/commands/deploy.js.map +1 -1
  40. package/dist/commands/doctor.js +2 -2
  41. package/dist/commands/init.d.ts.map +1 -1
  42. package/dist/commands/init.js +3 -0
  43. package/dist/commands/init.js.map +1 -1
  44. package/dist/commands/login.d.ts.map +1 -1
  45. package/dist/commands/login.js +96 -20
  46. package/dist/commands/login.js.map +1 -1
  47. package/dist/commands/logout.d.ts.map +1 -1
  48. package/dist/commands/logout.js +37 -5
  49. package/dist/commands/logout.js.map +1 -1
  50. package/dist/commands/mcp.d.ts +13 -0
  51. package/dist/commands/mcp.d.ts.map +1 -1
  52. package/dist/commands/mcp.js +184 -77
  53. package/dist/commands/mcp.js.map +1 -1
  54. package/dist/commands/projects.d.ts +2 -0
  55. package/dist/commands/projects.d.ts.map +1 -0
  56. package/dist/commands/projects.js +194 -0
  57. package/dist/commands/projects.js.map +1 -0
  58. package/dist/index.js +11 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/lib/finite-source-command-client.d.ts +3 -0
  61. package/dist/lib/finite-source-command-client.d.ts.map +1 -0
  62. package/dist/lib/finite-source-command-client.js +3 -0
  63. package/dist/lib/finite-source-command-client.js.map +1 -0
  64. package/dist/lib/mcp-io.d.ts +23 -0
  65. package/dist/lib/mcp-io.d.ts.map +1 -0
  66. package/dist/lib/mcp-io.js +185 -0
  67. package/dist/lib/mcp-io.js.map +1 -0
  68. package/dist/lib/mcp-source-commands.d.ts +17 -0
  69. package/dist/lib/mcp-source-commands.d.ts.map +1 -0
  70. package/dist/lib/mcp-source-commands.js +345 -0
  71. package/dist/lib/mcp-source-commands.js.map +1 -0
  72. package/dist/utils/api.d.ts +58 -8
  73. package/dist/utils/api.d.ts.map +1 -1
  74. package/dist/utils/api.js +86 -7
  75. package/dist/utils/api.js.map +1 -1
  76. package/dist/utils/apps-presentation.d.ts +11 -1
  77. package/dist/utils/apps-presentation.d.ts.map +1 -1
  78. package/dist/utils/apps-presentation.js +37 -0
  79. package/dist/utils/apps-presentation.js.map +1 -1
  80. package/dist/utils/args.d.ts.map +1 -1
  81. package/dist/utils/args.js +8 -1
  82. package/dist/utils/args.js.map +1 -1
  83. package/dist/utils/assets.d.ts +48 -1
  84. package/dist/utils/assets.d.ts.map +1 -1
  85. package/dist/utils/assets.js +185 -7
  86. package/dist/utils/assets.js.map +1 -1
  87. package/dist/utils/auth.d.ts +29 -2
  88. package/dist/utils/auth.d.ts.map +1 -1
  89. package/dist/utils/auth.js +164 -27
  90. package/dist/utils/auth.js.map +1 -1
  91. package/dist/utils/browser.d.ts +12 -0
  92. package/dist/utils/browser.d.ts.map +1 -1
  93. package/dist/utils/browser.js +37 -16
  94. package/dist/utils/browser.js.map +1 -1
  95. package/dist/utils/context.d.ts.map +1 -1
  96. package/dist/utils/context.js +2 -0
  97. package/dist/utils/context.js.map +1 -1
  98. package/dist/utils/deploy-follow.d.ts +4 -3
  99. package/dist/utils/deploy-follow.d.ts.map +1 -1
  100. package/dist/utils/deploy-follow.js +76 -17
  101. package/dist/utils/deploy-follow.js.map +1 -1
  102. package/dist/utils/detect.d.ts +49 -1
  103. package/dist/utils/detect.d.ts.map +1 -1
  104. package/dist/utils/detect.js +153 -12
  105. package/dist/utils/detect.js.map +1 -1
  106. package/dist/utils/ensure-auth.d.ts.map +1 -1
  107. package/dist/utils/ensure-auth.js +6 -2
  108. package/dist/utils/ensure-auth.js.map +1 -1
  109. package/dist/utils/package-metadata.js +1 -1
  110. package/dist/utils/project-context.d.ts +17 -0
  111. package/dist/utils/project-context.d.ts.map +1 -0
  112. package/dist/utils/project-context.js +96 -0
  113. package/dist/utils/project-context.js.map +1 -0
  114. package/dist/utils/project-lookup.d.ts +10 -0
  115. package/dist/utils/project-lookup.d.ts.map +1 -0
  116. package/dist/utils/project-lookup.js +52 -0
  117. package/dist/utils/project-lookup.js.map +1 -0
  118. package/package.json +7 -4
  119. package/skill/SKILL.md +15 -2
@@ -1,5 +1,5 @@
1
1
  import { requireAuth } from './api.js';
2
- import { authRequiredError } from './errors.js';
2
+ import { authRequiredError, CliError } from './errors.js';
3
3
  import { canPrompt, confirm } from './prompt.js';
4
4
  import { printLine } from './output.js';
5
5
  /**
@@ -12,7 +12,11 @@ export async function ensureAuth(apiOptions = {}) {
12
12
  await requireAuth(apiOptions);
13
13
  return;
14
14
  }
15
- catch {
15
+ catch (error) {
16
+ // Invalid environment/configuration is not a missing login. Preserve it
17
+ // instead of offering to create credentials in an accidentally named scope.
18
+ if (!(error instanceof CliError) || error.code !== 'AUTH_REQUIRED')
19
+ throw error;
16
20
  if (canPrompt() && (await confirm('You are not logged in. Log in now?', true))) {
17
21
  printLine('');
18
22
  const { loginCommand } = await import('../commands/login.js');
@@ -1 +1 @@
1
- {"version":3,"file":"ensure-auth.js","sourceRoot":"","sources":["../../src/utils/ensure-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA0B,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,aAAgC,EAAE;IACjE,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,SAAS,EAAE,IAAI,CAAC,MAAM,OAAO,CAAC,oCAAoC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;YAC/E,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;YAC9D,0EAA0E;YAC1E,wEAAwE;YACxE,oDAAoD;YACpD,MAAM,YAAY,CAAC;gBACjB,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9D,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aACrE,CAAC,CAAC;YACH,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,0CAA0C;YACzE,OAAO;QACT,CAAC;QACD,MAAM,iBAAiB,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"ensure-auth.js","sourceRoot":"","sources":["../../src/utils/ensure-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA0B,MAAM,UAAU,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,aAAgC,EAAE;IACjE,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wEAAwE;QACxE,4EAA4E;QAC5E,IAAI,CAAC,CAAC,KAAK,YAAY,QAAQ,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe;YAAE,MAAM,KAAK,CAAC;QAChF,IAAI,SAAS,EAAE,IAAI,CAAC,MAAM,OAAO,CAAC,oCAAoC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;YAC/E,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;YAC9D,0EAA0E;YAC1E,wEAAwE;YACxE,oDAAoD;YACpD,MAAM,YAAY,CAAC;gBACjB,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC9D,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;aACrE,CAAC,CAAC;YACH,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,0CAA0C;YACzE,OAAO;QACT,CAAC;QACD,MAAM,iBAAiB,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC"}
@@ -17,6 +17,6 @@ export function getCliVersion() {
17
17
  return readCliPackageJson().version ?? '0.1.0';
18
18
  }
19
19
  export function getSdkDependencyRange() {
20
- return readCliPackageJson().dependencies?.['@inquir/compute'] ?? '^0.1.0';
20
+ return readCliPackageJson().dependencies?.['@inquir/compute'] ?? '^0.4.0';
21
21
  }
22
22
  //# sourceMappingURL=package-metadata.js.map
@@ -0,0 +1,17 @@
1
+ import { type ApiRequestOptions } from './api.js';
2
+ export interface ProjectContext {
3
+ file: string;
4
+ /** Pin subsequent reads/writes to the workspace that /v1/me actually selected. */
5
+ apiOptions: ApiRequestOptions;
6
+ workspaceId: string;
7
+ }
8
+ /** Never infer identity/workspace from cached login data or a selector slug. */
9
+ export declare function resolveProjectContext(args: string[], apiOptions: ApiRequestOptions): Promise<ProjectContext>;
10
+ export declare function readProjectSelection(context: ProjectContext): Promise<string | undefined>;
11
+ export declare function writeProjectSelection(context: ProjectContext, projectId?: string): Promise<void>;
12
+ /** Explicit flag > selection for this directory/API/workspace/identity > server default. */
13
+ export declare function resolveCreateProject(args: string[], apiOptions: ApiRequestOptions): Promise<{
14
+ projectId?: string;
15
+ apiOptions: ApiRequestOptions;
16
+ }>;
17
+ //# sourceMappingURL=project-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-context.d.ts","sourceRoot":"","sources":["../../src/utils/project-context.ts"],"names":[],"mappings":"AAKA,OAAO,EAAS,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAMzD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,UAAU,EAAE,iBAAiB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;CACrB;AAiBD,gFAAgF;AAChF,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,EAAE,iBAAiB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAWzB;AAED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiB/F;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAatG;AAED,4FAA4F;AAC5F,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EAAE,EACd,UAAU,EAAE,iBAAiB,GAC5B,OAAO,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAsBhE"}
@@ -0,0 +1,96 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import fs from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { loadConfig } from '../sdk.js';
6
+ import { getMe } from './api.js';
7
+ import { readFlagValue, readWorkspaceDir } from './args.js';
8
+ import { resolveAuthConfig } from './auth.js';
9
+ import { CliError, ExitCode, usageError } from './errors.js';
10
+ import { resolveProject } from './project-lookup.js';
11
+ function digest(value) {
12
+ return createHash('sha256').update(JSON.stringify(value)).digest('hex');
13
+ }
14
+ async function contextDirectory(args, apiOptions) {
15
+ const auth = await resolveAuthConfig(apiOptions);
16
+ const api = new URL(auth.apiUrl);
17
+ api.pathname = api.pathname.replace(/\/+$/, '');
18
+ const root = await fs.realpath(loadConfig(readWorkspaceDir(args)).rootDir);
19
+ const directory = process.platform === 'win32' ? root.toLowerCase() : root;
20
+ return path.join(os.homedir(), '.inquir', 'project-contexts', digest([api.href, directory]));
21
+ }
22
+ /** Never infer identity/workspace from cached login data or a selector slug. */
23
+ export async function resolveProjectContext(args, apiOptions) {
24
+ const directory = await contextDirectory(args, apiOptions);
25
+ const auth = await resolveAuthConfig(apiOptions);
26
+ const me = await getMe(apiOptions);
27
+ const workspaceId = me.activeWorkspace.id;
28
+ const identity = me.user?.id ? `user:${me.user.id}` : `key:${digest(auth.token ?? auth.apiKey ?? '')}`;
29
+ return {
30
+ file: path.join(directory, `${digest([workspaceId, identity])}.json`),
31
+ workspaceId,
32
+ apiOptions: { ...apiOptions, workspaceId },
33
+ };
34
+ }
35
+ export async function readProjectSelection(context) {
36
+ let raw;
37
+ try {
38
+ raw = await fs.readFile(context.file, 'utf8');
39
+ }
40
+ catch (error) {
41
+ if (error.code === 'ENOENT')
42
+ return undefined;
43
+ throw error;
44
+ }
45
+ const selection = JSON.parse(raw);
46
+ if (typeof selection.projectId !== 'string' || !selection.projectId.trim()) {
47
+ throw new CliError('Stored project selection is invalid', {
48
+ code: 'INVALID_PROJECT_CONTEXT',
49
+ exitCode: ExitCode.ERROR,
50
+ fix: 'Run `inquir projects use --clear` to return to automatic project creation.',
51
+ });
52
+ }
53
+ return selection.projectId;
54
+ }
55
+ export async function writeProjectSelection(context, projectId) {
56
+ if (!projectId) {
57
+ await fs.rm(context.file, { force: true });
58
+ return;
59
+ }
60
+ await fs.mkdir(path.dirname(context.file), { recursive: true, mode: 0o700 });
61
+ const temporary = `${context.file}.${randomUUID()}.tmp`;
62
+ try {
63
+ await fs.writeFile(temporary, `${JSON.stringify({ projectId })}\n`, { mode: 0o600 });
64
+ await fs.rename(temporary, context.file);
65
+ }
66
+ finally {
67
+ await fs.rm(temporary, { force: true });
68
+ }
69
+ }
70
+ /** Explicit flag > selection for this directory/API/workspace/identity > server default. */
71
+ export async function resolveCreateProject(args, apiOptions) {
72
+ const terminator = args.indexOf('--');
73
+ const flags = terminator === -1 ? args : args.slice(0, terminator);
74
+ const hasProject = flags.some((arg) => arg === '--project' || arg.startsWith('--project='));
75
+ if (hasProject) {
76
+ const selector = readFlagValue(args, '--project')?.trim();
77
+ if (!selector)
78
+ throw usageError('Missing project selector', 'inquir apps create <name> --project <project>');
79
+ // A display name is resolved to its id here; the create endpoint still
80
+ // validates the project together with the application write.
81
+ return { projectId: (await resolveProject(selector, apiOptions)).id, apiOptions };
82
+ }
83
+ // Fresh CLI installations need no identity request merely to use the server default.
84
+ const directory = await contextDirectory(args, apiOptions);
85
+ try {
86
+ await fs.access(directory);
87
+ }
88
+ catch (error) {
89
+ if (error.code === 'ENOENT')
90
+ return { apiOptions };
91
+ throw error;
92
+ }
93
+ const context = await resolveProjectContext(args, apiOptions);
94
+ return { projectId: await readProjectSelection(context), apiOptions: context.apiOptions };
95
+ }
96
+ //# sourceMappingURL=project-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-context.js","sourceRoot":"","sources":["../../src/utils/project-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type ProjectDetail } from '../sdk.js';
2
+ import { type ApiRequestOptions } from './api.js';
3
+ export declare function isNotFound(error: unknown): boolean;
4
+ /**
5
+ * A project by the id or slug the API takes, or by its display name — the
6
+ * only thing the dashboard shows. A name is tried only after the API answered
7
+ * 404, so an id or slug always wins, and only a unique one is accepted.
8
+ */
9
+ export declare function resolveProject(selector: string, apiOptions: ApiRequestOptions): Promise<ProjectDetail>;
10
+ //# sourceMappingURL=project-lookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-lookup.d.ts","sourceRoot":"","sources":["../../src/utils/project-lookup.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAA4B,KAAK,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAM5E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAElD;AAkBD;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAgB5G"}
@@ -0,0 +1,52 @@
1
+ import { ApiError } from '../sdk.js';
2
+ import { getProject, listProjects } from './api.js';
3
+ import { CliError, ExitCode } from './errors.js';
4
+ /** A lookup by name reads the project list; bounded like the other list scans. */
5
+ const MAX_PROJECT_LIST_PAGES = 20;
6
+ export function isNotFound(error) {
7
+ return error instanceof ApiError && error.status === 404;
8
+ }
9
+ async function projectsNamed(name, apiOptions) {
10
+ const byId = new Map();
11
+ let cursor;
12
+ for (let page = 0; page < MAX_PROJECT_LIST_PAGES; page++) {
13
+ const result = await listProjects({ limit: 100, cursor }, apiOptions);
14
+ for (const project of result.items)
15
+ byId.set(project.id, project);
16
+ if (!result.nextCursor || result.nextCursor === cursor)
17
+ break;
18
+ cursor = result.nextCursor;
19
+ }
20
+ const projects = [...byId.values()];
21
+ const exact = projects.filter((project) => project.name === name);
22
+ if (exact.length > 0)
23
+ return exact;
24
+ const folded = name.toLocaleLowerCase();
25
+ return projects.filter((project) => project.name.toLocaleLowerCase() === folded);
26
+ }
27
+ /**
28
+ * A project by the id or slug the API takes, or by its display name — the
29
+ * only thing the dashboard shows. A name is tried only after the API answered
30
+ * 404, so an id or slug always wins, and only a unique one is accepted.
31
+ */
32
+ export async function resolveProject(selector, apiOptions) {
33
+ try {
34
+ return await getProject(selector, apiOptions);
35
+ }
36
+ catch (error) {
37
+ if (!isNotFound(error))
38
+ throw error;
39
+ const named = await projectsNamed(selector, apiOptions);
40
+ if (named.length === 1)
41
+ return getProject(named[0].id, apiOptions);
42
+ if (named.length > 1) {
43
+ throw new CliError(`Several projects are named '${selector}'`, {
44
+ code: 'AMBIGUOUS_PROJECT',
45
+ exitCode: ExitCode.USAGE,
46
+ fix: `Use the slug of the one you mean: ${named.map((project) => project.slug).join(', ')}`,
47
+ });
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ //# sourceMappingURL=project-lookup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-lookup.js","sourceRoot":"","sources":["../../src/utils/project-lookup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAoC,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,YAAY,EAA0B,MAAM,UAAU,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEjD,kFAAkF;AAClF,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAElC,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,OAAO,KAAK,YAAY,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC;AAC3D,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,UAA6B;IACtE,MAAM,IAAI,GAAG,IAAI,GAAG,EAAmB,CAAC;IACxC,IAAI,MAA0B,CAAC;IAC/B,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,sBAAsB,EAAE,IAAI,EAAE,EAAE,CAAC;QACzD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,UAAU,CAAC,CAAC;QACtE,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,KAAK;YAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM;YAAE,MAAM;QAC9D,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;IAC7B,CAAC;IACD,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACxC,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,MAAM,CAAC,CAAC;AACnF,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,UAA6B;IAClF,IAAI,CAAC;QACH,OAAO,MAAM,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,MAAM,KAAK,CAAC;QACpC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QACxD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QACnE,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,QAAQ,CAAC,+BAA+B,QAAQ,GAAG,EAAE;gBAC7D,IAAI,EAAE,mBAAmB;gBACzB,QAAQ,EAAE,QAAQ,CAAC,KAAK;gBACxB,GAAG,EAAE,qCAAqC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aAC5F,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inquir/compute-cli",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Workspace-first CLI for Inquir Compute.",
6
6
  "bin": {
@@ -12,16 +12,19 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
15
- "build": "npm --prefix ../.. run build --workspace @inquir/compute && tsc -p tsconfig.json",
15
+ "build": "npm run clean && npm --prefix ../.. run build --workspace @inquir/compute && tsc -p tsconfig.json",
16
16
  "build:self": "tsc -p tsconfig.json",
17
- "prepublishOnly": "npm run clean && npm run build",
17
+ "prepack": "npm run build",
18
18
  "test": "npx vitest run -c vitest.config.ts"
19
19
  },
20
20
  "publishConfig": {
21
21
  "access": "public"
22
22
  },
23
+ "engines": {
24
+ "node": ">=22"
25
+ },
23
26
  "dependencies": {
24
- "@inquir/compute": "^0.2.0",
27
+ "@inquir/compute": "^0.4.0",
25
28
  "tsx": "^4.19.2"
26
29
  },
27
30
  "devDependencies": {
package/skill/SKILL.md CHANGED
@@ -35,21 +35,34 @@ Detection rules:
35
35
 
36
36
  Overrides when detection guesses wrong: `--runtime`, `--handler <module.export>`, `--mode handler|web`, `--start "<cmd>"`.
37
37
 
38
+ ## Databases (Postgres / Redis)
39
+
40
+ - `inquir apps create mydb --template postgres|redis` — one command from nothing to a running database: image, persistent volume, private TCP port, generated password, first release. `--volume-runner <runner>` puts it on a worker; that needs the operator's mirror of the template image, and the refusal (`APP_TEMPLATE_IMAGE_NOT_MIRRORED`) says so.
41
+ - `inquir apps connect mydb web` — writes the connection URL into another app's env as `DATABASE_URL` / `REDIS_URL`; applies on that app's next release. Prefer this: the password never passes through you.
42
+ - `inquir apps connection-url mydb` — prints the live URL with credentials in it (and into shell history); use only when the consumer is not an app on the platform.
43
+ - `inquir apps backups mydb [list|create|restore <id>|delete <id>]` — volume snapshots. `restore` **overwrites the volume** and stops the app while it runs; it asks for confirmation, so non-interactively it needs `--yes`.
44
+
38
45
  ## MCP tools (preferred for agents)
39
46
 
40
47
  Register once: `claude mcp add inquir -- inquir mcp`
41
48
 
42
49
  - `deploy {path, name?, start?, env?}` — detect + deploy a directory; returns detection reasons, deploy status, and error logs on failure.
43
50
  - `invoke {function, payload}` — run a function and get result + logs.
44
- - `exec {function, command, target?}` — run a shell command inside the function's container (its runtime image + code). `target: "source"` (default) is read-write: use it for installing deps, running tests, debugging.
51
+ - `exec {function, command, requestId, target?}` — submit an asynchronous command against a private source snapshot. Before calling, generate and retain one lowercase UUID v4 `requestId` per intent. A repeated UUID only observes; it never creates another execution. Finite execution must be enabled on the server; an unavailable response never falls back to writable published source. `target: "release"` uses the existing read-only release execution and needs no UUID.
52
+ - `source_command_status {requestId, waitMs?}` — read execution state/output; optional bounded GET polling. An interrupted wait does not cancel execution or release capacity.
53
+ - `source_command_reconcile {requestId}` — explicitly apply retained output if the original source is still current. Inspect `APPLIED`, `CONFLICT`, or `workspaceFailure`; never automatically rerun a command after conflict.
54
+ - `source_command_cancel {requestId}` — request durable cancellation. `CANCEL_REQUESTED` is intent, not a stopped-container receipt; `PUBLICATION_COMMITTED` means cancellation is too late.
55
+ - `source_command_resume {requestId, action: "status" | "submit"}` — reload the privately retained operation after restart. Use `status` first; `submit` explicitly retries the same saved bytes and UUID after an uncertain submission. Resume requires the same API, credential and workspace. Records contain command/env secrets and no credentials; preserve the CLI user profile's private filesystem permissions. Optional `inquir mcp --source-session <stable-conversation-id>` also binds JSON-RPC request IDs across reconnects; do not reuse that namespace for unrelated conversations.
45
56
  - `list_invocations {function}` — recent runs with errors and logs: the debugging entry point.
46
57
  - `deploy_status {deployId}`, `rollback {function, deployId}`, `list_functions`.
47
58
 
59
+ The stdio server admits four working calls, including at most one deploy/rollback, plus two source-control or deploy-status calls. A busy response starts no work; retain the source UUID when retrying. Ping and cancellation notifications remain available while work waits. Each input frame is limited to 64 KiB. HTTP responses are limited to 2 MiB for source commands and 4 MiB otherwise, with a 60-second timeout per request including body reads. Output waits for the reader, retaining at most sixteen replies or 8 MiB; a broken or stalled pipe closes observation. Disconnecting never sends a job cancellation.
60
+
48
61
  ## Debug loop that works
49
62
 
50
63
  1. `deploy` → read `deploy.error` and status.
51
64
  2. If failing at runtime: `list_invocations` → read logs.
52
- 3. Reproduce inside the container: `exec {command: "npm test"}` or `exec {command: "python -c '...'"}`.
65
+ 3. Submit a source command with a retained UUID, then read `source_command_status`. Review output before explicitly reconciling source changes. For a read-only release check use `exec {function: "my-function", command: "npm test", target: "release"}`.
53
66
  4. Fix code locally, `deploy` again. Deploys are versioned; `rollback` restores any previous success.
54
67
 
55
68
  ## Contracts that matter