specforge-cli 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/commands/access.d.ts +3 -0
  2. package/dist/commands/access.d.ts.map +1 -0
  3. package/dist/commands/access.js +98 -0
  4. package/dist/commands/access.js.map +1 -0
  5. package/dist/commands/amendments.d.ts +3 -0
  6. package/dist/commands/amendments.d.ts.map +1 -0
  7. package/dist/commands/amendments.js +61 -0
  8. package/dist/commands/amendments.js.map +1 -0
  9. package/dist/commands/audit.d.ts +3 -0
  10. package/dist/commands/audit.d.ts.map +1 -0
  11. package/dist/commands/audit.js +73 -0
  12. package/dist/commands/audit.js.map +1 -0
  13. package/dist/commands/auth.d.ts +3 -0
  14. package/dist/commands/auth.d.ts.map +1 -0
  15. package/dist/commands/auth.js +275 -0
  16. package/dist/commands/auth.js.map +1 -0
  17. package/dist/commands/config.d.ts +3 -0
  18. package/dist/commands/config.d.ts.map +1 -0
  19. package/dist/commands/config.js +66 -0
  20. package/dist/commands/config.js.map +1 -0
  21. package/dist/commands/diff.d.ts +3 -0
  22. package/dist/commands/diff.d.ts.map +1 -0
  23. package/dist/commands/diff.js +85 -0
  24. package/dist/commands/diff.js.map +1 -0
  25. package/dist/commands/export.d.ts +3 -0
  26. package/dist/commands/export.d.ts.map +1 -0
  27. package/dist/commands/export.js +162 -0
  28. package/dist/commands/export.js.map +1 -0
  29. package/dist/commands/features.d.ts +3 -0
  30. package/dist/commands/features.d.ts.map +1 -0
  31. package/dist/commands/features.js +134 -0
  32. package/dist/commands/features.js.map +1 -0
  33. package/dist/commands/media.d.ts +3 -0
  34. package/dist/commands/media.d.ts.map +1 -0
  35. package/dist/commands/media.js +142 -0
  36. package/dist/commands/media.js.map +1 -0
  37. package/dist/commands/notifications.d.ts +3 -0
  38. package/dist/commands/notifications.d.ts.map +1 -0
  39. package/dist/commands/notifications.js +75 -0
  40. package/dist/commands/notifications.js.map +1 -0
  41. package/dist/commands/org.d.ts +3 -0
  42. package/dist/commands/org.d.ts.map +1 -0
  43. package/dist/commands/org.js +145 -0
  44. package/dist/commands/org.js.map +1 -0
  45. package/dist/commands/project.d.ts +3 -0
  46. package/dist/commands/project.d.ts.map +1 -0
  47. package/dist/commands/project.js +205 -0
  48. package/dist/commands/project.js.map +1 -0
  49. package/dist/commands/review.d.ts +3 -0
  50. package/dist/commands/review.d.ts.map +1 -0
  51. package/dist/commands/review.js +102 -0
  52. package/dist/commands/review.js.map +1 -0
  53. package/dist/commands/sign.d.ts +3 -0
  54. package/dist/commands/sign.d.ts.map +1 -0
  55. package/dist/commands/sign.js +152 -0
  56. package/dist/commands/sign.js.map +1 -0
  57. package/dist/commands/spec.d.ts +3 -0
  58. package/dist/commands/spec.d.ts.map +1 -0
  59. package/dist/commands/spec.js +157 -0
  60. package/dist/commands/spec.js.map +1 -0
  61. package/dist/commands/user.d.ts +3 -0
  62. package/dist/commands/user.d.ts.map +1 -0
  63. package/dist/commands/user.js +117 -0
  64. package/dist/commands/user.js.map +1 -0
  65. package/dist/commands/verify.d.ts +3 -0
  66. package/dist/commands/verify.d.ts.map +1 -0
  67. package/dist/commands/verify.js +59 -0
  68. package/dist/commands/verify.js.map +1 -0
  69. package/dist/commands/version.d.ts +3 -0
  70. package/dist/commands/version.d.ts.map +1 -0
  71. package/dist/commands/version.js +167 -0
  72. package/dist/commands/version.js.map +1 -0
  73. package/dist/commands/webhook.d.ts +3 -0
  74. package/dist/commands/webhook.d.ts.map +1 -0
  75. package/dist/commands/webhook.js +201 -0
  76. package/dist/commands/webhook.js.map +1 -0
  77. package/dist/index.d.ts +24 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +82 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/lib/auth.d.ts +24 -0
  82. package/dist/lib/auth.d.ts.map +1 -0
  83. package/dist/lib/auth.js +92 -0
  84. package/dist/lib/auth.js.map +1 -0
  85. package/dist/lib/client.d.ts +6 -0
  86. package/dist/lib/client.d.ts.map +1 -0
  87. package/dist/lib/client.js +8 -0
  88. package/dist/lib/client.js.map +1 -0
  89. package/dist/lib/config.d.ts +15 -0
  90. package/dist/lib/config.d.ts.map +1 -0
  91. package/dist/lib/config.js +41 -0
  92. package/dist/lib/config.js.map +1 -0
  93. package/dist/lib/errors.d.ts +21 -0
  94. package/dist/lib/errors.d.ts.map +1 -0
  95. package/dist/lib/errors.js +41 -0
  96. package/dist/lib/errors.js.map +1 -0
  97. package/dist/lib/exit-codes.d.ts +30 -0
  98. package/dist/lib/exit-codes.d.ts.map +1 -0
  99. package/dist/lib/exit-codes.js +41 -0
  100. package/dist/lib/exit-codes.js.map +1 -0
  101. package/dist/lib/output.d.ts +7 -0
  102. package/dist/lib/output.d.ts.map +1 -0
  103. package/dist/lib/output.js +60 -0
  104. package/dist/lib/output.js.map +1 -0
  105. package/package.json +42 -0
@@ -0,0 +1,92 @@
1
+ import { loadConfig, saveConfig } from "./config";
2
+ import { ExitCode } from "./exit-codes";
3
+ /**
4
+ * Resolve auth credentials by priority:
5
+ * 1. SPECFORGE_API_KEY env var
6
+ * 2. --api-key CLI flag
7
+ * 3. Config file credential
8
+ * 4. Legacy config accessToken (auto-migrate)
9
+ * 5. None → error + exit
10
+ */
11
+ export function resolveAuth(args) {
12
+ // 1. Env var (highest priority — CI/CD override)
13
+ const envKey = process.env.SPECFORGE_API_KEY;
14
+ if (envKey) {
15
+ return { token: envKey, source: "env", expiresAt: null };
16
+ }
17
+ // 2. CLI flag (one-off override)
18
+ if (args?.apiKey) {
19
+ return { token: args.apiKey, source: "api-key", expiresAt: null };
20
+ }
21
+ // 3. Config file (persistent login)
22
+ const config = loadConfig();
23
+ // 3a. New credential format
24
+ if (config.credential?.token) {
25
+ if (config.credential.expiresAt && new Date(config.credential.expiresAt) < new Date()) {
26
+ console.error("Session expired. Run `specforge auth login` to re-authenticate.");
27
+ process.exit(ExitCode.AUTH_ERROR);
28
+ }
29
+ return config.credential;
30
+ }
31
+ // 3b. Legacy format (auto-migrate)
32
+ if (config.accessToken) {
33
+ const cred = {
34
+ token: config.accessToken,
35
+ source: "oauth",
36
+ expiresAt: null,
37
+ };
38
+ // Auto-migrate to new format
39
+ saveCredential(cred);
40
+ return cred;
41
+ }
42
+ // 4. No credentials
43
+ console.error("Not authenticated. Run `specforge auth login` first.");
44
+ process.exit(ExitCode.AUTH_ERROR);
45
+ }
46
+ export function saveCredential(credential) {
47
+ const config = loadConfig();
48
+ const updated = {
49
+ ...config,
50
+ credential,
51
+ };
52
+ delete updated.accessToken; // Remove legacy field
53
+ saveConfig(updated);
54
+ }
55
+ export function clearCredential() {
56
+ const config = loadConfig();
57
+ const updated = { ...config };
58
+ delete updated.credential;
59
+ delete updated.accessToken;
60
+ saveConfig(updated);
61
+ }
62
+ export function getAuthStatus() {
63
+ // Check env var directly (avoids process.exit from resolveAuth)
64
+ const envKey = process.env.SPECFORGE_API_KEY;
65
+ if (envKey) {
66
+ return {
67
+ authenticated: true,
68
+ credential: { token: envKey, source: "env", expiresAt: null },
69
+ };
70
+ }
71
+ const config = loadConfig();
72
+ // Check new credential format
73
+ if (config.credential?.token) {
74
+ if (config.credential.expiresAt && new Date(config.credential.expiresAt) < new Date()) {
75
+ return { authenticated: false };
76
+ }
77
+ return { authenticated: true, credential: config.credential };
78
+ }
79
+ // Check legacy format
80
+ if (config.accessToken) {
81
+ return {
82
+ authenticated: true,
83
+ credential: {
84
+ token: config.accessToken,
85
+ source: "oauth",
86
+ expiresAt: null,
87
+ },
88
+ };
89
+ }
90
+ return { authenticated: false };
91
+ }
92
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type CliClientConfig = {
2
+ readonly baseUrl: string;
3
+ readonly accessToken: string;
4
+ };
5
+ export declare function createCliClient(config: CliClientConfig): import("specforge-sdk").SpecKitClient;
6
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,yCAKtD"}
@@ -0,0 +1,8 @@
1
+ import { createClient } from "specforge-sdk";
2
+ export function createCliClient(config) {
3
+ return createClient({
4
+ baseUrl: config.baseUrl,
5
+ auth: { accessToken: config.accessToken },
6
+ });
7
+ }
8
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAO7C,MAAM,UAAU,eAAe,CAAC,MAAuB;IACtD,OAAO,YAAY,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,IAAI,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE;KACzC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface SpecForgeConfig {
2
+ baseUrl: string;
3
+ accessToken?: string;
4
+ credential?: {
5
+ token: string;
6
+ source: "env" | "api-key" | "oauth";
7
+ expiresAt: string | null;
8
+ };
9
+ defaultProjectId?: string;
10
+ }
11
+ export declare function loadConfig(): SpecForgeConfig;
12
+ export declare function saveConfig(config: SpecForgeConfig): void;
13
+ export declare function getConfigPath(): string;
14
+ export declare function requireAuth(config: SpecForgeConfig): string;
15
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,KAAK,GAAG,SAAS,GAAG,OAAO,CAAC;QACpC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;IACF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAYD,wBAAgB,UAAU,IAAI,eAAe,CAU5C;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAGxD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAM3D"}
@@ -0,0 +1,41 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { ExitCode } from "./exit-codes";
5
+ const CONFIG_DIR = join(homedir(), ".specforge");
6
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
7
+ const DEFAULT_CONFIG = {
8
+ baseUrl: "https://api.specforge.dev",
9
+ };
10
+ function ensureConfigDir() {
11
+ if (!existsSync(CONFIG_DIR)) {
12
+ mkdirSync(CONFIG_DIR, { recursive: true });
13
+ }
14
+ }
15
+ export function loadConfig() {
16
+ if (!existsSync(CONFIG_FILE)) {
17
+ return { ...DEFAULT_CONFIG };
18
+ }
19
+ try {
20
+ const raw = readFileSync(CONFIG_FILE, "utf-8");
21
+ return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
22
+ }
23
+ catch {
24
+ return { ...DEFAULT_CONFIG };
25
+ }
26
+ }
27
+ export function saveConfig(config) {
28
+ ensureConfigDir();
29
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
30
+ }
31
+ export function getConfigPath() {
32
+ return CONFIG_FILE;
33
+ }
34
+ export function requireAuth(config) {
35
+ if (!config.accessToken) {
36
+ console.error("Not authenticated. Run `specforge auth login` first.");
37
+ process.exit(ExitCode.AUTH_ERROR);
38
+ }
39
+ return config.accessToken;
40
+ }
41
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AACjD,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAapD,MAAM,cAAc,GAAoB;IACvC,OAAO,EAAE,2BAA2B;CACpC,CAAC;AAEF,SAAS,eAAe;IACvB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;AACF,CAAC;AAED,MAAM,UAAU,UAAU;IACzB,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9B,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC9B,CAAC;IACD,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC9B,CAAC;AACF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAuB;IACjD,eAAe,EAAE,CAAC;IAClB,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,aAAa;IAC5B,OAAO,WAAW,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAuB;IAClD,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;QACtE,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,MAAM,CAAC,WAAW,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,21 @@
1
+ export { ExitCode, exitCodeFromStatus } from "./exit-codes";
2
+ export declare function handleError(error: unknown): never;
3
+ interface ApiErrorDetail {
4
+ field: string;
5
+ message: string;
6
+ }
7
+ interface ApiError {
8
+ code?: string;
9
+ message?: string;
10
+ status?: number;
11
+ error?: ApiError;
12
+ details?: ApiErrorDetail[];
13
+ }
14
+ export declare function handleApiResult(result: {
15
+ data?: unknown;
16
+ error?: ApiError;
17
+ response?: {
18
+ status: number;
19
+ };
20
+ }): unknown;
21
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE5D,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAuBjD;AAED,UAAU,cAAc;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,QAAQ;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACvC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,QAAQ,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9B,GAAG,OAAO,CAcV"}
@@ -0,0 +1,41 @@
1
+ import { isSpecKitError } from "specforge-sdk";
2
+ import { ExitCode, exitCodeFromStatus } from "./exit-codes";
3
+ export { ExitCode, exitCodeFromStatus } from "./exit-codes";
4
+ export function handleError(error) {
5
+ if (isSpecKitError(error)) {
6
+ const code = exitCodeFromStatus(error.status);
7
+ console.error(`Error [${error.code}]: ${error.message}`);
8
+ if (error.details?.length) {
9
+ for (const detail of error.details) {
10
+ console.error(` - ${detail.field}: ${detail.message}`);
11
+ }
12
+ }
13
+ process.exit(code);
14
+ }
15
+ if (error instanceof Error) {
16
+ if (error.message.includes("fetch") || error.message.includes("ECONNREFUSED")) {
17
+ console.error(`Network error: ${error.message}`);
18
+ process.exit(ExitCode.GENERAL_ERROR);
19
+ }
20
+ console.error(`Error: ${error.message}`);
21
+ process.exit(ExitCode.GENERAL_ERROR);
22
+ }
23
+ console.error("An unexpected error occurred.");
24
+ process.exit(ExitCode.GENERAL_ERROR);
25
+ }
26
+ export function handleApiResult(result) {
27
+ if (result.error) {
28
+ const err = result.error.error ?? result.error;
29
+ const status = result.response?.status ?? err.status ?? 500;
30
+ const code = exitCodeFromStatus(status);
31
+ console.error(`Error [${err.code ?? "UNKNOWN"}]: ${err.message ?? "Unknown error"}`);
32
+ if (err.details?.length) {
33
+ for (const detail of err.details) {
34
+ console.error(` - ${detail.field}: ${detail.message}`);
35
+ }
36
+ }
37
+ process.exit(code);
38
+ }
39
+ return result.data;
40
+ }
41
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE5D,MAAM,UAAU,WAAW,CAAC,KAAc;IACzC,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACzD,IAAI,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;YAC3B,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACpC,OAAO,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,CAAC;QACF,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAC/E,OAAO,CAAC,KAAK,CAAC,kBAAkB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACjD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,UAAU,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACzC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IACtC,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;AACtC,CAAC;AAeD,MAAM,UAAU,eAAe,CAAC,MAI/B;IACA,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;QAC/C,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;QAC5D,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACxC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,IAAI,IAAI,SAAS,MAAM,GAAG,CAAC,OAAO,IAAI,eAAe,EAAE,CAAC,CAAC;QACrF,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;YACzB,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAClC,OAAO,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,CAAC;QACF,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACpB,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * CLI exit codes as defined in the CLI contract.
3
+ *
4
+ * @see specs/001-spec-versioning-saas/contracts/cli-commands.md
5
+ *
6
+ * | Code | Meaning |
7
+ * | ---- | ---------------- |
8
+ * | 0 | Success |
9
+ * | 1 | General error |
10
+ * | 2 | Auth error |
11
+ * | 3 | Validation error |
12
+ * | 4 | Not found |
13
+ * | 5 | Permission denied|
14
+ * | 6 | Conflict |
15
+ */
16
+ export declare const ExitCode: {
17
+ readonly SUCCESS: 0;
18
+ readonly GENERAL_ERROR: 1;
19
+ readonly AUTH_ERROR: 2;
20
+ readonly VALIDATION_ERROR: 3;
21
+ readonly NOT_FOUND: 4;
22
+ readonly PERMISSION_DENIED: 5;
23
+ readonly CONFLICT: 6;
24
+ };
25
+ export type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];
26
+ /**
27
+ * Map an HTTP status code to the appropriate CLI exit code.
28
+ */
29
+ export declare function exitCodeFromStatus(status: number): ExitCode;
30
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../../src/lib/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ;;;;;;;;CAQX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAEhE;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAO3D"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * CLI exit codes as defined in the CLI contract.
3
+ *
4
+ * @see specs/001-spec-versioning-saas/contracts/cli-commands.md
5
+ *
6
+ * | Code | Meaning |
7
+ * | ---- | ---------------- |
8
+ * | 0 | Success |
9
+ * | 1 | General error |
10
+ * | 2 | Auth error |
11
+ * | 3 | Validation error |
12
+ * | 4 | Not found |
13
+ * | 5 | Permission denied|
14
+ * | 6 | Conflict |
15
+ */
16
+ export const ExitCode = {
17
+ SUCCESS: 0,
18
+ GENERAL_ERROR: 1,
19
+ AUTH_ERROR: 2,
20
+ VALIDATION_ERROR: 3,
21
+ NOT_FOUND: 4,
22
+ PERMISSION_DENIED: 5,
23
+ CONFLICT: 6,
24
+ };
25
+ /**
26
+ * Map an HTTP status code to the appropriate CLI exit code.
27
+ */
28
+ export function exitCodeFromStatus(status) {
29
+ if (status === 401)
30
+ return ExitCode.AUTH_ERROR;
31
+ if (status === 403)
32
+ return ExitCode.PERMISSION_DENIED;
33
+ if (status === 404)
34
+ return ExitCode.NOT_FOUND;
35
+ if (status === 400 || status === 422)
36
+ return ExitCode.VALIDATION_ERROR;
37
+ if (status === 409)
38
+ return ExitCode.CONFLICT;
39
+ return ExitCode.GENERAL_ERROR;
40
+ }
41
+ //# sourceMappingURL=exit-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/lib/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACvB,OAAO,EAAE,CAAC;IACV,aAAa,EAAE,CAAC;IAChB,UAAU,EAAE,CAAC;IACb,gBAAgB,EAAE,CAAC;IACnB,SAAS,EAAE,CAAC;IACZ,iBAAiB,EAAE,CAAC;IACpB,QAAQ,EAAE,CAAC;CACF,CAAC;AAIX;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAChD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC,UAAU,CAAC;IAC/C,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC,iBAAiB,CAAC;IACtD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC,SAAS,CAAC;IAC9C,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC,gBAAgB,CAAC;IACvE,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAC7C,OAAO,QAAQ,CAAC,aAAa,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Output helpers for JSON and table formatting.
3
+ */
4
+ export declare function outputJson(data: unknown): void;
5
+ export declare function outputTable(rows: Record<string, unknown>[], columns?: string[]): void;
6
+ export declare function outputResult(data: unknown, json: boolean, columns?: string[]): void;
7
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAE9C;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAuCrF;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAmBnF"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Output helpers for JSON and table formatting.
3
+ */
4
+ export function outputJson(data) {
5
+ console.log(JSON.stringify(data, null, 2));
6
+ }
7
+ export function outputTable(rows, columns) {
8
+ if (rows.length === 0) {
9
+ console.log("No results.");
10
+ return;
11
+ }
12
+ const firstRow = rows[0];
13
+ const keys = columns ?? (firstRow ? Object.keys(firstRow) : []);
14
+ // Calculate column widths
15
+ const widths = new Map();
16
+ for (const key of keys) {
17
+ widths.set(key, key.length);
18
+ }
19
+ for (const row of rows) {
20
+ for (const key of keys) {
21
+ const value = String(row[key] ?? "");
22
+ const current = widths.get(key) ?? 0;
23
+ if (value.length > current) {
24
+ widths.set(key, Math.min(value.length, 60));
25
+ }
26
+ }
27
+ }
28
+ // Header
29
+ const header = keys.map((k) => k.toUpperCase().padEnd(widths.get(k) ?? 0)).join(" ");
30
+ console.log(header);
31
+ console.log(keys.map((k) => "-".repeat(widths.get(k) ?? 0)).join(" "));
32
+ // Rows
33
+ for (const row of rows) {
34
+ const line = keys
35
+ .map((k) => {
36
+ const value = String(row[k] ?? "");
37
+ return value.slice(0, 60).padEnd(widths.get(k) ?? 0);
38
+ })
39
+ .join(" ");
40
+ console.log(line);
41
+ }
42
+ }
43
+ export function outputResult(data, json, columns) {
44
+ if (json) {
45
+ outputJson(data);
46
+ return;
47
+ }
48
+ if (Array.isArray(data)) {
49
+ outputTable(data, columns);
50
+ return;
51
+ }
52
+ if (typeof data === "object" && data !== null) {
53
+ for (const [key, value] of Object.entries(data)) {
54
+ console.log(`${key}: ${typeof value === "object" ? JSON.stringify(value) : value}`);
55
+ }
56
+ return;
57
+ }
58
+ console.log(String(data));
59
+ }
60
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "specforge-cli",
3
+ "version": "0.1.1",
4
+ "description": "SpecForge CLI — specification versioning and signing from the terminal",
5
+ "type": "module",
6
+ "bin": {
7
+ "specforge": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "typecheck": "tsc --noEmit",
16
+ "build": "tsc",
17
+ "prepublishOnly": "tsc",
18
+ "test": "vitest run"
19
+ },
20
+ "keywords": [
21
+ "specforge",
22
+ "cli",
23
+ "specifications",
24
+ "versioning",
25
+ "signing"
26
+ ],
27
+ "license": "MIT",
28
+ "author": "Léo Brival",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/leobrival/specifications",
32
+ "directory": "packages/cli"
33
+ },
34
+ "dependencies": {
35
+ "specforge-sdk": "0.1.0",
36
+ "citty": "^0.1.6"
37
+ },
38
+ "devDependencies": {
39
+ "typescript": "^5",
40
+ "vitest": "^4.1.0"
41
+ }
42
+ }