@spekn/cli 1.0.0 → 1.0.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.
- package/README.md +58 -0
- package/dist/main.js +3707 -611
- package/dist/tui/index.mjs +2 -2
- package/package.json +29 -12
- package/dist/__tests__/export-cli.test.d.ts +0 -1
- package/dist/__tests__/export-cli.test.js +0 -70
- package/dist/__tests__/tui-args-policy.test.d.ts +0 -1
- package/dist/__tests__/tui-args-policy.test.js +0 -50
- package/dist/acp-S2MHZOAD.mjs +0 -23
- package/dist/acp-UCCI44JY.mjs +0 -25
- package/dist/auth/credentials-store.d.ts +0 -2
- package/dist/auth/credentials-store.js +0 -5
- package/dist/auth/device-flow.d.ts +0 -36
- package/dist/auth/device-flow.js +0 -189
- package/dist/auth/jwt.d.ts +0 -1
- package/dist/auth/jwt.js +0 -6
- package/dist/auth/session.d.ts +0 -67
- package/dist/auth/session.js +0 -86
- package/dist/auth-login.d.ts +0 -34
- package/dist/auth-login.js +0 -202
- package/dist/auth-logout.d.ts +0 -25
- package/dist/auth-logout.js +0 -115
- package/dist/auth-status.d.ts +0 -24
- package/dist/auth-status.js +0 -109
- package/dist/backlog-generate.d.ts +0 -11
- package/dist/backlog-generate.js +0 -308
- package/dist/backlog-health.d.ts +0 -11
- package/dist/backlog-health.js +0 -287
- package/dist/bridge-login.d.ts +0 -40
- package/dist/bridge-login.js +0 -277
- package/dist/chunk-3PAYRI4G.mjs +0 -2428
- package/dist/chunk-M4CS3A25.mjs +0 -2426
- package/dist/commands/auth/login.d.ts +0 -30
- package/dist/commands/auth/login.js +0 -164
- package/dist/commands/auth/logout.d.ts +0 -25
- package/dist/commands/auth/logout.js +0 -115
- package/dist/commands/auth/status.d.ts +0 -24
- package/dist/commands/auth/status.js +0 -109
- package/dist/commands/backlog/generate.d.ts +0 -11
- package/dist/commands/backlog/generate.js +0 -308
- package/dist/commands/backlog/health.d.ts +0 -11
- package/dist/commands/backlog/health.js +0 -287
- package/dist/commands/bridge/login.d.ts +0 -36
- package/dist/commands/bridge/login.js +0 -258
- package/dist/commands/export.d.ts +0 -35
- package/dist/commands/export.js +0 -485
- package/dist/commands/marketplace-export.d.ts +0 -21
- package/dist/commands/marketplace-export.js +0 -214
- package/dist/commands/project-clean.d.ts +0 -1
- package/dist/commands/project-clean.js +0 -126
- package/dist/commands/repo/common.d.ts +0 -105
- package/dist/commands/repo/common.js +0 -775
- package/dist/commands/repo/detach.d.ts +0 -2
- package/dist/commands/repo/detach.js +0 -120
- package/dist/commands/repo/register.d.ts +0 -21
- package/dist/commands/repo/register.js +0 -175
- package/dist/commands/repo/sync.d.ts +0 -22
- package/dist/commands/repo/sync.js +0 -873
- package/dist/commands/skills-import-local.d.ts +0 -16
- package/dist/commands/skills-import-local.js +0 -352
- package/dist/commands/spec/drift-check.d.ts +0 -3
- package/dist/commands/spec/drift-check.js +0 -186
- package/dist/commands/spec/frontmatter.d.ts +0 -11
- package/dist/commands/spec/frontmatter.js +0 -219
- package/dist/commands/spec/lint.d.ts +0 -11
- package/dist/commands/spec/lint.js +0 -499
- package/dist/commands/spec/parse.d.ts +0 -11
- package/dist/commands/spec/parse.js +0 -162
- package/dist/export.d.ts +0 -35
- package/dist/export.js +0 -485
- package/dist/main.d.ts +0 -1
- package/dist/marketplace-export.d.ts +0 -21
- package/dist/marketplace-export.js +0 -214
- package/dist/project-clean.d.ts +0 -1
- package/dist/project-clean.js +0 -126
- package/dist/project-context.d.ts +0 -99
- package/dist/project-context.js +0 -376
- package/dist/repo-common.d.ts +0 -101
- package/dist/repo-common.js +0 -671
- package/dist/repo-detach.d.ts +0 -2
- package/dist/repo-detach.js +0 -102
- package/dist/repo-ingest.d.ts +0 -29
- package/dist/repo-ingest.js +0 -305
- package/dist/repo-register.d.ts +0 -21
- package/dist/repo-register.js +0 -175
- package/dist/repo-sync.d.ts +0 -16
- package/dist/repo-sync.js +0 -152
- package/dist/resources/prompt-loader.d.ts +0 -1
- package/dist/resources/prompt-loader.js +0 -62
- package/dist/skills-import-local.d.ts +0 -16
- package/dist/skills-import-local.js +0 -352
- package/dist/spec-drift-check.d.ts +0 -3
- package/dist/spec-drift-check.js +0 -186
- package/dist/spec-frontmatter.d.ts +0 -11
- package/dist/spec-frontmatter.js +0 -219
- package/dist/spec-lint.d.ts +0 -11
- package/dist/spec-lint.js +0 -499
- package/dist/spec-parse.d.ts +0 -11
- package/dist/spec-parse.js +0 -162
- package/dist/stubs/dotenv.d.ts +0 -5
- package/dist/stubs/dotenv.js +0 -6
- package/dist/stubs/typeorm.d.ts +0 -22
- package/dist/stubs/typeorm.js +0 -28
- package/dist/tui/app.d.ts +0 -7
- package/dist/tui/app.js +0 -122
- package/dist/tui/args.d.ts +0 -8
- package/dist/tui/args.js +0 -57
- package/dist/tui/capabilities/policy.d.ts +0 -7
- package/dist/tui/capabilities/policy.js +0 -64
- package/dist/tui/components/frame.d.ts +0 -8
- package/dist/tui/components/frame.js +0 -8
- package/dist/tui/components/status-bar.d.ts +0 -8
- package/dist/tui/components/status-bar.js +0 -8
- package/dist/tui/index.d.ts +0 -2
- package/dist/tui/index.js +0 -23
- package/dist/tui/keymap/use-global-keymap.d.ts +0 -19
- package/dist/tui/keymap/use-global-keymap.js +0 -82
- package/dist/tui/navigation/nav-items.d.ts +0 -3
- package/dist/tui/navigation/nav-items.js +0 -18
- package/dist/tui/screens/bridge.d.ts +0 -8
- package/dist/tui/screens/bridge.js +0 -19
- package/dist/tui/screens/decisions.d.ts +0 -5
- package/dist/tui/screens/decisions.js +0 -28
- package/dist/tui/screens/export.d.ts +0 -5
- package/dist/tui/screens/export.js +0 -16
- package/dist/tui/screens/home.d.ts +0 -5
- package/dist/tui/screens/home.js +0 -33
- package/dist/tui/screens/locked.d.ts +0 -5
- package/dist/tui/screens/locked.js +0 -9
- package/dist/tui/screens/specs.d.ts +0 -5
- package/dist/tui/screens/specs.js +0 -31
- package/dist/tui/services/client.d.ts +0 -1
- package/dist/tui/services/client.js +0 -18
- package/dist/tui/services/context-service.d.ts +0 -19
- package/dist/tui/services/context-service.js +0 -246
- package/dist/tui/shared-enums.d.ts +0 -16
- package/dist/tui/shared-enums.js +0 -19
- package/dist/tui/state/use-app-state.d.ts +0 -35
- package/dist/tui/state/use-app-state.js +0 -177
- package/dist/tui/types.d.ts +0 -77
- package/dist/tui/types.js +0 -2
- package/dist/tui-bundle.d.ts +0 -1
- package/dist/tui-bundle.js +0 -5
- package/dist/tui-entry.mjs +0 -1407
- package/dist/utils/cli-runtime.d.ts +0 -5
- package/dist/utils/cli-runtime.js +0 -22
- package/dist/utils/help-error.d.ts +0 -7
- package/dist/utils/help-error.js +0 -14
- package/dist/utils/interaction.d.ts +0 -19
- package/dist/utils/interaction.js +0 -93
- package/dist/utils/structured-log.d.ts +0 -7
- package/dist/utils/structured-log.js +0 -112
- package/dist/utils/trpc-url.d.ts +0 -4
- package/dist/utils/trpc-url.js +0 -15
package/dist/repo-detach.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
-
if (k2 === undefined) k2 = k;
|
|
5
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
-
}
|
|
9
|
-
Object.defineProperty(o, k2, desc);
|
|
10
|
-
}) : (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
o[k2] = m[k];
|
|
13
|
-
}));
|
|
14
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
-
}) : function(o, v) {
|
|
17
|
-
o["default"] = v;
|
|
18
|
-
});
|
|
19
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
-
var ownKeys = function(o) {
|
|
21
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
-
var ar = [];
|
|
23
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
-
return ar;
|
|
25
|
-
};
|
|
26
|
-
return ownKeys(o);
|
|
27
|
-
};
|
|
28
|
-
return function (mod) {
|
|
29
|
-
if (mod && mod.__esModule) return mod;
|
|
30
|
-
var result = {};
|
|
31
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
-
__setModuleDefault(result, mod);
|
|
33
|
-
return result;
|
|
34
|
-
};
|
|
35
|
-
})();
|
|
36
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
exports.runRepoDetachCli = runRepoDetachCli;
|
|
38
|
-
const fs = __importStar(require("node:fs"));
|
|
39
|
-
const path = __importStar(require("node:path"));
|
|
40
|
-
function printHelp(stderr) {
|
|
41
|
-
stderr(`
|
|
42
|
-
repo detach - Detach the current repository from local Spekn project context
|
|
43
|
-
|
|
44
|
-
USAGE:
|
|
45
|
-
spekn repo detach [options]
|
|
46
|
-
|
|
47
|
-
OPTIONS:
|
|
48
|
-
--path <dir> Repository root path (default: current directory)
|
|
49
|
-
--help Show this help message
|
|
50
|
-
|
|
51
|
-
EXAMPLES:
|
|
52
|
-
spekn repo detach
|
|
53
|
-
spekn repo detach --path /path/to/repo
|
|
54
|
-
`);
|
|
55
|
-
}
|
|
56
|
-
function parseArgs(args) {
|
|
57
|
-
let repoPath = process.cwd();
|
|
58
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
59
|
-
const arg = args[index];
|
|
60
|
-
if (arg === '--help') {
|
|
61
|
-
throw new Error('HELP_REQUESTED');
|
|
62
|
-
}
|
|
63
|
-
if (arg === '--path' && args[index + 1]) {
|
|
64
|
-
repoPath = path.resolve(args[index + 1]);
|
|
65
|
-
index += 1;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (arg?.startsWith('--path=')) {
|
|
69
|
-
repoPath = path.resolve(arg.slice('--path='.length));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return { repoPath };
|
|
73
|
-
}
|
|
74
|
-
async function runRepoDetachCli(args) {
|
|
75
|
-
try {
|
|
76
|
-
const options = parseArgs(args);
|
|
77
|
-
const localContextPath = path.join(options.repoPath, '.spekn');
|
|
78
|
-
if (!fs.existsSync(localContextPath)) {
|
|
79
|
-
process.stdout.write('No local .spekn context file found. Nothing to detach.\n');
|
|
80
|
-
return 0;
|
|
81
|
-
}
|
|
82
|
-
fs.unlinkSync(localContextPath);
|
|
83
|
-
process.stdout.write(`Detached repository context (${localContextPath}).\n`);
|
|
84
|
-
return 0;
|
|
85
|
-
}
|
|
86
|
-
catch (error) {
|
|
87
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
88
|
-
if (message === 'HELP_REQUESTED') {
|
|
89
|
-
printHelp(process.stderr.write.bind(process.stderr));
|
|
90
|
-
return 0;
|
|
91
|
-
}
|
|
92
|
-
process.stderr.write(`Error: ${message}\n`);
|
|
93
|
-
return 1;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
async function main() {
|
|
97
|
-
const exitCode = await runRepoDetachCli(process.argv.slice(2));
|
|
98
|
-
process.exit(exitCode);
|
|
99
|
-
}
|
|
100
|
-
if (require.main === module) {
|
|
101
|
-
void main();
|
|
102
|
-
}
|
package/dist/repo-ingest.d.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* repo ingest CLI command
|
|
4
|
-
*
|
|
5
|
-
* Scans the current (or specified) git repository for governance files
|
|
6
|
-
* (CLAUDE.md, AGENTS.md, .cursorrules, specs/*.md, etc.) and ingests
|
|
7
|
-
* them into a Spekn project via the ingestion API.
|
|
8
|
-
*
|
|
9
|
-
* Usage: spekn repo ingest --project-id <uuid> [--path <dir>] [--dry-run] [--api-url <url>]
|
|
10
|
-
*/
|
|
11
|
-
import { CredentialsStore } from "./auth/credentials-store";
|
|
12
|
-
interface CLIOptions {
|
|
13
|
-
projectId: string;
|
|
14
|
-
repoPath: string;
|
|
15
|
-
dryRun: boolean;
|
|
16
|
-
apiUrl: string;
|
|
17
|
-
}
|
|
18
|
-
interface Deps {
|
|
19
|
-
stdout: (content: string) => void;
|
|
20
|
-
stderr: (content: string) => void;
|
|
21
|
-
credentialsStore: CredentialsStore;
|
|
22
|
-
readFile: (filePath: string) => string;
|
|
23
|
-
fileExists: (filePath: string) => boolean;
|
|
24
|
-
readDir: (dirPath: string) => string[];
|
|
25
|
-
}
|
|
26
|
-
declare function parseArgs(args: string[]): CLIOptions;
|
|
27
|
-
export declare function runRepoIngestCli(args: string[], deps?: Deps): Promise<number>;
|
|
28
|
-
declare function main(): Promise<void>;
|
|
29
|
-
export { main, parseArgs };
|
package/dist/repo-ingest.js
DELETED
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/**
|
|
4
|
-
* repo ingest CLI command
|
|
5
|
-
*
|
|
6
|
-
* Scans the current (or specified) git repository for governance files
|
|
7
|
-
* (CLAUDE.md, AGENTS.md, .cursorrules, specs/*.md, etc.) and ingests
|
|
8
|
-
* them into a Spekn project via the ingestion API.
|
|
9
|
-
*
|
|
10
|
-
* Usage: spekn repo ingest --project-id <uuid> [--path <dir>] [--dry-run] [--api-url <url>]
|
|
11
|
-
*/
|
|
12
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
-
if (k2 === undefined) k2 = k;
|
|
14
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
-
}
|
|
18
|
-
Object.defineProperty(o, k2, desc);
|
|
19
|
-
}) : (function(o, m, k, k2) {
|
|
20
|
-
if (k2 === undefined) k2 = k;
|
|
21
|
-
o[k2] = m[k];
|
|
22
|
-
}));
|
|
23
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
-
}) : function(o, v) {
|
|
26
|
-
o["default"] = v;
|
|
27
|
-
});
|
|
28
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
-
var ownKeys = function(o) {
|
|
30
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
-
var ar = [];
|
|
32
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
-
return ar;
|
|
34
|
-
};
|
|
35
|
-
return ownKeys(o);
|
|
36
|
-
};
|
|
37
|
-
return function (mod) {
|
|
38
|
-
if (mod && mod.__esModule) return mod;
|
|
39
|
-
var result = {};
|
|
40
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
-
__setModuleDefault(result, mod);
|
|
42
|
-
return result;
|
|
43
|
-
};
|
|
44
|
-
})();
|
|
45
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.runRepoIngestCli = runRepoIngestCli;
|
|
47
|
-
exports.main = main;
|
|
48
|
-
exports.parseArgs = parseArgs;
|
|
49
|
-
const fs = __importStar(require("node:fs"));
|
|
50
|
-
const path = __importStar(require("node:path"));
|
|
51
|
-
const client_1 = require("@trpc/client");
|
|
52
|
-
const credentials_store_1 = require("./auth/credentials-store");
|
|
53
|
-
const trpc_url_1 = require("./utils/trpc-url");
|
|
54
|
-
const help_error_1 = require("./utils/help-error");
|
|
55
|
-
// ── Governance file patterns ────────────────────────────────────────
|
|
56
|
-
/** Well-known governance files to look for at the repo root. */
|
|
57
|
-
const ROOT_FILES = [
|
|
58
|
-
"CLAUDE.md",
|
|
59
|
-
".claude/CLAUDE.md",
|
|
60
|
-
"AGENTS.md",
|
|
61
|
-
".cursorrules",
|
|
62
|
-
".github/copilot-instructions.md",
|
|
63
|
-
];
|
|
64
|
-
/** Directories to scan recursively for markdown governance files. */
|
|
65
|
-
const SCAN_DIRS = ["specs", "decisions", "ADR"];
|
|
66
|
-
/** Directories to always skip during recursive scanning. */
|
|
67
|
-
const IGNORE_DIRS = new Set([
|
|
68
|
-
"node_modules",
|
|
69
|
-
"dist",
|
|
70
|
-
".git",
|
|
71
|
-
"build",
|
|
72
|
-
"coverage",
|
|
73
|
-
".next",
|
|
74
|
-
".nuxt",
|
|
75
|
-
"__pycache__",
|
|
76
|
-
".venv",
|
|
77
|
-
]);
|
|
78
|
-
const defaultDeps = {
|
|
79
|
-
stdout: (content) => process.stdout.write(content),
|
|
80
|
-
stderr: (content) => process.stderr.write(content),
|
|
81
|
-
credentialsStore: new credentials_store_1.CredentialsStore(),
|
|
82
|
-
readFile: (filePath) => fs.readFileSync(filePath, "utf-8"),
|
|
83
|
-
fileExists: (filePath) => fs.existsSync(filePath) && fs.statSync(filePath).isFile(),
|
|
84
|
-
readDir: (dirPath) => {
|
|
85
|
-
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory())
|
|
86
|
-
return [];
|
|
87
|
-
return collectMarkdownFiles(dirPath);
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
// ── Helpers ─────────────────────────────────────────────────────────
|
|
91
|
-
function collectMarkdownFiles(dirPath) {
|
|
92
|
-
const results = [];
|
|
93
|
-
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
94
|
-
for (const entry of entries) {
|
|
95
|
-
if (IGNORE_DIRS.has(entry.name))
|
|
96
|
-
continue;
|
|
97
|
-
const full = path.join(dirPath, entry.name);
|
|
98
|
-
if (entry.isDirectory()) {
|
|
99
|
-
results.push(...collectMarkdownFiles(full));
|
|
100
|
-
}
|
|
101
|
-
else if (entry.isFile() && /\.mdx?$/.test(entry.name)) {
|
|
102
|
-
results.push(full);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return results;
|
|
106
|
-
}
|
|
107
|
-
function printHelp(stderr) {
|
|
108
|
-
stderr(`
|
|
109
|
-
repo ingest - Ingest local governance files into a Spekn project
|
|
110
|
-
|
|
111
|
-
USAGE:
|
|
112
|
-
spekn repo ingest --project-id <uuid> [options]
|
|
113
|
-
|
|
114
|
-
OPTIONS:
|
|
115
|
-
--project-id <uuid> Project ID to ingest into (required)
|
|
116
|
-
--path <dir> Repository root path (default: current directory)
|
|
117
|
-
--dry-run Analyze files without persisting to the server
|
|
118
|
-
--api-url <url> API base URL (default: SPEKN_API_URL or http://localhost:3000)
|
|
119
|
-
--help Show this help message
|
|
120
|
-
|
|
121
|
-
ENVIRONMENT:
|
|
122
|
-
SPEKN_API_URL API base URL
|
|
123
|
-
SPEKN_AUTH_TOKEN Bearer token for authentication
|
|
124
|
-
SPEKN_ORGANIZATION_ID Organization ID header
|
|
125
|
-
|
|
126
|
-
DETECTED FILES:
|
|
127
|
-
Root: CLAUDE.md, .claude/CLAUDE.md, AGENTS.md, .cursorrules,
|
|
128
|
-
.github/copilot-instructions.md
|
|
129
|
-
Dirs: specs/**/*.md, decisions/**/*.md, ADR/**/*.md
|
|
130
|
-
|
|
131
|
-
EXAMPLES:
|
|
132
|
-
spekn repo ingest --project-id 11111111-1111-4111-8111-111111111111
|
|
133
|
-
spekn repo ingest --project-id 11111111-1111-4111-8111-111111111111 --dry-run
|
|
134
|
-
spekn repo ingest --project-id 11111111-1111-4111-8111-111111111111 --path /path/to/repo
|
|
135
|
-
`);
|
|
136
|
-
}
|
|
137
|
-
function parseArgs(args) {
|
|
138
|
-
let projectId = "";
|
|
139
|
-
let repoPath = ".";
|
|
140
|
-
let dryRun = false;
|
|
141
|
-
let apiUrl = process.env.SPEKN_API_URL ?? "http://localhost:3000";
|
|
142
|
-
for (let index = 0; index < args.length; index++) {
|
|
143
|
-
const arg = args[index];
|
|
144
|
-
if (arg === "--help" || arg === "-h") {
|
|
145
|
-
throw new help_error_1.HelpRequestedError();
|
|
146
|
-
}
|
|
147
|
-
if (arg === "--project-id" && args[index + 1]) {
|
|
148
|
-
projectId = args[++index];
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
if (arg?.startsWith("--project-id=")) {
|
|
152
|
-
projectId = arg.slice("--project-id=".length);
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
if (arg === "--path" && args[index + 1]) {
|
|
156
|
-
repoPath = args[++index];
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
if (arg?.startsWith("--path=")) {
|
|
160
|
-
repoPath = arg.slice("--path=".length);
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
if (arg === "--dry-run") {
|
|
164
|
-
dryRun = true;
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
if (arg === "--api-url" && args[index + 1]) {
|
|
168
|
-
apiUrl = args[++index];
|
|
169
|
-
continue;
|
|
170
|
-
}
|
|
171
|
-
if (arg?.startsWith("--api-url=")) {
|
|
172
|
-
apiUrl = arg.slice("--api-url=".length);
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
if (!projectId) {
|
|
177
|
-
throw new Error("Missing required argument: --project-id <uuid>");
|
|
178
|
-
}
|
|
179
|
-
return { projectId, repoPath: path.resolve(repoPath), dryRun, apiUrl };
|
|
180
|
-
}
|
|
181
|
-
// ── Main ────────────────────────────────────────────────────────────
|
|
182
|
-
async function runRepoIngestCli(args, deps = defaultDeps) {
|
|
183
|
-
try {
|
|
184
|
-
const options = parseArgs(args);
|
|
185
|
-
// Resolve auth
|
|
186
|
-
const storedToken = await deps.credentialsStore.getValidToken();
|
|
187
|
-
const authToken = storedToken ?? process.env.SPEKN_AUTH_TOKEN;
|
|
188
|
-
const storedCreds = deps.credentialsStore.load();
|
|
189
|
-
const organizationId = storedCreds?.organizationId ?? process.env.SPEKN_ORGANIZATION_ID ?? "";
|
|
190
|
-
if (!authToken) {
|
|
191
|
-
deps.stderr("Error: Not authenticated. Run 'spekn auth login' first.\n");
|
|
192
|
-
return 1;
|
|
193
|
-
}
|
|
194
|
-
if (!organizationId) {
|
|
195
|
-
deps.stderr("Error: No organization ID. Re-run 'spekn auth login' or set SPEKN_ORGANIZATION_ID.\n");
|
|
196
|
-
return 1;
|
|
197
|
-
}
|
|
198
|
-
// Discover governance files
|
|
199
|
-
const discovered = [];
|
|
200
|
-
for (const file of ROOT_FILES) {
|
|
201
|
-
const abs = path.join(options.repoPath, file);
|
|
202
|
-
if (deps.fileExists(abs)) {
|
|
203
|
-
discovered.push({ relativePath: file, absolutePath: abs });
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
for (const dir of SCAN_DIRS) {
|
|
207
|
-
const abs = path.join(options.repoPath, dir);
|
|
208
|
-
const files = deps.readDir(abs);
|
|
209
|
-
for (const file of files) {
|
|
210
|
-
const rel = path.relative(options.repoPath, file);
|
|
211
|
-
discovered.push({ relativePath: rel, absolutePath: file });
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
// Also check for .claude/rules/*.md
|
|
215
|
-
const rulesDir = path.join(options.repoPath, ".claude", "rules");
|
|
216
|
-
const ruleFiles = deps.readDir(rulesDir);
|
|
217
|
-
for (const file of ruleFiles) {
|
|
218
|
-
const rel = path.relative(options.repoPath, file);
|
|
219
|
-
discovered.push({ relativePath: rel, absolutePath: file });
|
|
220
|
-
}
|
|
221
|
-
if (discovered.length === 0) {
|
|
222
|
-
deps.stdout("No governance files found in " + options.repoPath + "\n");
|
|
223
|
-
return 0;
|
|
224
|
-
}
|
|
225
|
-
deps.stdout(`Found ${discovered.length} governance file(s) in ${options.repoPath}\n\n`);
|
|
226
|
-
// Create tRPC client
|
|
227
|
-
const client = (0, client_1.createTRPCProxyClient)({
|
|
228
|
-
links: [
|
|
229
|
-
(0, client_1.httpBatchLink)({
|
|
230
|
-
url: (0, trpc_url_1.normalizeTrpcUrl)(options.apiUrl),
|
|
231
|
-
headers: {
|
|
232
|
-
"x-organization-id": organizationId,
|
|
233
|
-
authorization: `Bearer ${authToken}`,
|
|
234
|
-
},
|
|
235
|
-
}),
|
|
236
|
-
],
|
|
237
|
-
});
|
|
238
|
-
let successCount = 0;
|
|
239
|
-
let failCount = 0;
|
|
240
|
-
for (const file of discovered) {
|
|
241
|
-
deps.stdout(` ${file.relativePath}`);
|
|
242
|
-
const content = deps.readFile(file.absolutePath);
|
|
243
|
-
if (!content.trim()) {
|
|
244
|
-
deps.stdout(" ... skipped (empty)\n");
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
try {
|
|
248
|
-
// Analyze content via server
|
|
249
|
-
const result = await client.ingestion.analyzeContent.mutate({
|
|
250
|
-
content,
|
|
251
|
-
filename: path.basename(file.relativePath),
|
|
252
|
-
});
|
|
253
|
-
const meta = result.metadata;
|
|
254
|
-
const layerCounts = {
|
|
255
|
-
constraints: result.layers.constraints.length,
|
|
256
|
-
requirements: result.layers.requirements.length,
|
|
257
|
-
technicalContext: result.layers.technicalContext.length,
|
|
258
|
-
implementationGuidance: result.layers.implementationGuidance.length,
|
|
259
|
-
};
|
|
260
|
-
const totalSections = Object.values(layerCounts).reduce((a, b) => a + b, 0);
|
|
261
|
-
deps.stdout(` ... ${meta.sourceFormat} (confidence: ${(meta.confidence * 100).toFixed(0)}%, ${totalSections} sections)`);
|
|
262
|
-
if (meta.warnings.length > 0) {
|
|
263
|
-
deps.stdout(`\n Warnings: ${meta.warnings.join(", ")}`);
|
|
264
|
-
}
|
|
265
|
-
if (options.dryRun) {
|
|
266
|
-
deps.stdout(" [dry-run]\n");
|
|
267
|
-
successCount++;
|
|
268
|
-
continue;
|
|
269
|
-
}
|
|
270
|
-
// Persist to project
|
|
271
|
-
await client.ingestion.confirmIngestion.mutate({
|
|
272
|
-
projectId: options.projectId,
|
|
273
|
-
result,
|
|
274
|
-
});
|
|
275
|
-
deps.stdout(" ... ingested\n");
|
|
276
|
-
successCount++;
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
280
|
-
deps.stdout(` ... FAILED: ${message}\n`);
|
|
281
|
-
failCount++;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
deps.stdout(`\nDone: ${successCount} ingested, ${failCount} failed` +
|
|
285
|
-
(options.dryRun ? " (dry-run)" : "") +
|
|
286
|
-
"\n");
|
|
287
|
-
return failCount > 0 ? 1 : 0;
|
|
288
|
-
}
|
|
289
|
-
catch (error) {
|
|
290
|
-
if (error instanceof help_error_1.HelpRequestedError) {
|
|
291
|
-
printHelp(deps.stderr);
|
|
292
|
-
return 0;
|
|
293
|
-
}
|
|
294
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
295
|
-
deps.stderr(`Error: ${message}\n`);
|
|
296
|
-
return 1;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
async function main() {
|
|
300
|
-
const exitCode = await runRepoIngestCli(process.argv.slice(2));
|
|
301
|
-
process.exit(exitCode);
|
|
302
|
-
}
|
|
303
|
-
if (require.main === module) {
|
|
304
|
-
void main();
|
|
305
|
-
}
|
package/dist/repo-register.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* repo-register CLI command
|
|
4
|
-
*
|
|
5
|
-
* Registers the current git repository with a Spekn project and optionally
|
|
6
|
-
* runs AI-powered analysis to discover specs, assess governance, and create
|
|
7
|
-
* improvement specifications.
|
|
8
|
-
*
|
|
9
|
-
* Usage: spekn repo register --project-id <uuid> [--primary] [--analyze] [--no-analyze]
|
|
10
|
-
* [--agent <name>] [--path <dir>] [--dry-run] [--api-url <url>]
|
|
11
|
-
*/
|
|
12
|
-
import { type CommonOptions, type Deps } from "./repo-common";
|
|
13
|
-
export { repoNameFromUrl, resolveDefaultBranch, discoverFiles, buildAnalysisPrompt, executeAcpSession, runAnalysisWithAgent, verifyMcpServer, } from "./repo-common";
|
|
14
|
-
export type { DiscoveredFile } from "./repo-common";
|
|
15
|
-
interface RegisterOptions extends CommonOptions {
|
|
16
|
-
primary: boolean;
|
|
17
|
-
}
|
|
18
|
-
declare function parseArgs(args: string[]): RegisterOptions;
|
|
19
|
-
export declare function runRepoRegisterCli(args: string[], deps?: Deps): Promise<number>;
|
|
20
|
-
declare function main(): Promise<void>;
|
|
21
|
-
export { main, parseArgs };
|
package/dist/repo-register.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/**
|
|
4
|
-
* repo-register CLI command
|
|
5
|
-
*
|
|
6
|
-
* Registers the current git repository with a Spekn project and optionally
|
|
7
|
-
* runs AI-powered analysis to discover specs, assess governance, and create
|
|
8
|
-
* improvement specifications.
|
|
9
|
-
*
|
|
10
|
-
* Usage: spekn repo register --project-id <uuid> [--primary] [--analyze] [--no-analyze]
|
|
11
|
-
* [--agent <name>] [--path <dir>] [--dry-run] [--api-url <url>]
|
|
12
|
-
*/
|
|
13
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.verifyMcpServer = exports.runAnalysisWithAgent = exports.executeAcpSession = exports.buildAnalysisPrompt = exports.discoverFiles = exports.resolveDefaultBranch = exports.repoNameFromUrl = void 0;
|
|
15
|
-
exports.runRepoRegisterCli = runRepoRegisterCli;
|
|
16
|
-
exports.main = main;
|
|
17
|
-
exports.parseArgs = parseArgs;
|
|
18
|
-
const repo_common_1 = require("./repo-common");
|
|
19
|
-
const project_context_1 = require("./project-context");
|
|
20
|
-
const structured_log_1 = require("./utils/structured-log");
|
|
21
|
-
// Re-export shared utilities for backward compatibility
|
|
22
|
-
var repo_common_2 = require("./repo-common");
|
|
23
|
-
Object.defineProperty(exports, "repoNameFromUrl", { enumerable: true, get: function () { return repo_common_2.repoNameFromUrl; } });
|
|
24
|
-
Object.defineProperty(exports, "resolveDefaultBranch", { enumerable: true, get: function () { return repo_common_2.resolveDefaultBranch; } });
|
|
25
|
-
Object.defineProperty(exports, "discoverFiles", { enumerable: true, get: function () { return repo_common_2.discoverFiles; } });
|
|
26
|
-
Object.defineProperty(exports, "buildAnalysisPrompt", { enumerable: true, get: function () { return repo_common_2.buildAnalysisPrompt; } });
|
|
27
|
-
Object.defineProperty(exports, "executeAcpSession", { enumerable: true, get: function () { return repo_common_2.executeAcpSession; } });
|
|
28
|
-
Object.defineProperty(exports, "runAnalysisWithAgent", { enumerable: true, get: function () { return repo_common_2.runAnalysisWithAgent; } });
|
|
29
|
-
Object.defineProperty(exports, "verifyMcpServer", { enumerable: true, get: function () { return repo_common_2.verifyMcpServer; } });
|
|
30
|
-
// ── Help & Args ─────────────────────────────────────────────────────
|
|
31
|
-
function printHelp(stderr) {
|
|
32
|
-
stderr(`
|
|
33
|
-
repo register - Register the current git repository with a Spekn project
|
|
34
|
-
|
|
35
|
-
USAGE:
|
|
36
|
-
spekn repo register --project-id <uuid> [options]
|
|
37
|
-
|
|
38
|
-
OPTIONS:
|
|
39
|
-
--project-id <uuid> Project ID to register the repo under (optional if .spekn/context is present)
|
|
40
|
-
--primary Set this repository as the primary repo for the project
|
|
41
|
-
--analyze Run AI analysis after registration (default: true)
|
|
42
|
-
--no-analyze Skip AI analysis (metadata-only registration)
|
|
43
|
-
--agent <name> Force a specific agent (claude, codex, opencode, etc.)
|
|
44
|
-
--path <dir> Repository root path (default: current directory)
|
|
45
|
-
--dry-run Discover files only, skip AI analysis
|
|
46
|
-
--api-url <url> API base URL (default: SPEKN_API_URL or https://app.spekn.com)
|
|
47
|
-
--mcp-url <url> MCP HTTP server URL (default: MCP_HTTP_URL or https://app.spekn.com/mcp)
|
|
48
|
-
--debug Show detailed debug output (tokens, HTTP exchanges)
|
|
49
|
-
--help Show this help message
|
|
50
|
-
|
|
51
|
-
ENVIRONMENT:
|
|
52
|
-
SPEKN_API_URL API base URL
|
|
53
|
-
SPEKN_AUTH_TOKEN Bearer token for authentication
|
|
54
|
-
SPEKN_ORGANIZATION_ID Organization ID header
|
|
55
|
-
MCP_HTTP_URL MCP HTTP server URL (default: https://app.spekn.com/mcp)
|
|
56
|
-
AGENT_ARGS Override agent CLI args (skips ACP registry resolution)
|
|
57
|
-
|
|
58
|
-
EXAMPLES:
|
|
59
|
-
spekn repo register --project-id 11111111-1111-4111-8111-111111111111
|
|
60
|
-
spekn repo register --project-id 11111111-1111-4111-8111-111111111111 --primary
|
|
61
|
-
spekn repo register --project-id 11111111-1111-4111-8111-111111111111 --no-analyze
|
|
62
|
-
spekn repo register --project-id 11111111-1111-4111-8111-111111111111 --dry-run
|
|
63
|
-
spekn repo register --project-id 11111111-1111-4111-8111-111111111111 --agent claude
|
|
64
|
-
spekn repo register --project-id 11111111-1111-4111-8111-111111111111 --path /path/to/repo
|
|
65
|
-
`);
|
|
66
|
-
}
|
|
67
|
-
function parseArgs(args) {
|
|
68
|
-
const opts = { ...(0, repo_common_1.commonDefaults)(true), primary: false };
|
|
69
|
-
for (let i = 0; i < args.length;) {
|
|
70
|
-
const consumed = (0, repo_common_1.parseCommonFlag)(args, i, opts);
|
|
71
|
-
if (consumed > 0) {
|
|
72
|
-
i += consumed;
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (args[i] === "--primary") {
|
|
76
|
-
opts.primary = true;
|
|
77
|
-
i++;
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
i++; // skip unknown
|
|
81
|
-
}
|
|
82
|
-
return (0, repo_common_1.finalizeOptions)(opts);
|
|
83
|
-
}
|
|
84
|
-
// ── Main ────────────────────────────────────────────────────────────
|
|
85
|
-
async function runRepoRegisterCli(args, deps = repo_common_1.defaultDeps) {
|
|
86
|
-
try {
|
|
87
|
-
const options = parseArgs(args);
|
|
88
|
-
(0, structured_log_1.appendCliStructuredLog)({
|
|
89
|
-
source: "cli.repo.register",
|
|
90
|
-
level: "info",
|
|
91
|
-
message: "Starting repo register",
|
|
92
|
-
details: { repoPath: options.repoPath, analyze: options.analyze, apiUrl: options.apiUrl },
|
|
93
|
-
});
|
|
94
|
-
const { authToken, organizationId, projectId } = await (0, repo_common_1.resolveAuth)(deps, {
|
|
95
|
-
projectId: options.projectId,
|
|
96
|
-
repoPath: options.repoPath,
|
|
97
|
-
});
|
|
98
|
-
// ── Phase 1: Register repository metadata ──────────────────────
|
|
99
|
-
const git = (0, repo_common_1.readGitMetadata)(options.repoPath, deps);
|
|
100
|
-
if (!git)
|
|
101
|
-
return 1;
|
|
102
|
-
deps.stdout(`Registering repository "${git.name}" (${git.remoteUrl})\n`);
|
|
103
|
-
deps.stdout(` Default branch : ${git.defaultBranch}\n`);
|
|
104
|
-
deps.stdout(` Project : ${projectId}\n`);
|
|
105
|
-
if (options.primary)
|
|
106
|
-
deps.stdout(" Primary : yes\n");
|
|
107
|
-
const client = (0, repo_common_1.createApiClient)(options.apiUrl, authToken, organizationId);
|
|
108
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
109
|
-
const result = await client.gitRepository.create.mutate({
|
|
110
|
-
projectId,
|
|
111
|
-
name: git.name,
|
|
112
|
-
repositoryUrl: git.remoteUrl,
|
|
113
|
-
defaultBranch: git.defaultBranch,
|
|
114
|
-
isPrimary: options.primary,
|
|
115
|
-
});
|
|
116
|
-
deps.stdout(`Repository registered successfully. ID: ${result.id}\n`);
|
|
117
|
-
(0, structured_log_1.appendCliStructuredLog)({
|
|
118
|
-
source: "cli.repo.register",
|
|
119
|
-
level: "info",
|
|
120
|
-
message: "Repository metadata registered",
|
|
121
|
-
details: { projectId, organizationId, repositoryId: result.id },
|
|
122
|
-
});
|
|
123
|
-
(0, project_context_1.persistProjectContext)(options.repoPath, { projectId, organizationId: organizationId || undefined });
|
|
124
|
-
(0, project_context_1.ensureGitignoreHasSpekn)(options.repoPath);
|
|
125
|
-
// ── Phase 2: AI analysis (optional) ─────────────────────────────
|
|
126
|
-
if (!options.analyze)
|
|
127
|
-
return 0;
|
|
128
|
-
if (!organizationId) {
|
|
129
|
-
deps.stderr("Warning: No organization ID. Skipping AI analysis. Re-run 'spekn auth login' or set SPEKN_ORGANIZATION_ID.\n");
|
|
130
|
-
return 0;
|
|
131
|
-
}
|
|
132
|
-
const exitCode = await (0, repo_common_1.runAnalysisPhase)({ ...options, projectId }, authToken ?? "", deps, organizationId);
|
|
133
|
-
(0, structured_log_1.appendCliStructuredLog)({
|
|
134
|
-
source: "cli.repo.register",
|
|
135
|
-
level: exitCode === 0 ? "info" : "error",
|
|
136
|
-
message: "Repo register completed",
|
|
137
|
-
details: { exitCode, analyzed: options.analyze, projectId },
|
|
138
|
-
});
|
|
139
|
-
return exitCode;
|
|
140
|
-
}
|
|
141
|
-
catch (error) {
|
|
142
|
-
if (error instanceof repo_common_1.HelpRequestedError) {
|
|
143
|
-
printHelp(deps.stderr);
|
|
144
|
-
return 0;
|
|
145
|
-
}
|
|
146
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
147
|
-
deps.stderr(`Error: ${message}\n`);
|
|
148
|
-
// Provide specific guidance for common errors
|
|
149
|
-
if (message.includes('organization') || message.includes('Organization')) {
|
|
150
|
-
deps.stderr(`\n`);
|
|
151
|
-
deps.stderr(`Organization context is required. Try one of:\n`);
|
|
152
|
-
deps.stderr(` 1. Run 'spekn auth login' to authenticate and select an organization\n`);
|
|
153
|
-
deps.stderr(` 2. Set SPEKN_ORGANIZATION_ID environment variable\n`);
|
|
154
|
-
deps.stderr(` 3. Pass --organization-id explicitly (if supported)\n`);
|
|
155
|
-
}
|
|
156
|
-
else if (message.includes('credentials') || message.includes('auth') || message.includes('token')) {
|
|
157
|
-
deps.stderr(`\n`);
|
|
158
|
-
deps.stderr(`Authentication required. Run:\n`);
|
|
159
|
-
deps.stderr(` spekn auth login\n`);
|
|
160
|
-
}
|
|
161
|
-
(0, structured_log_1.appendCliStructuredLog)({
|
|
162
|
-
source: "cli.repo.register",
|
|
163
|
-
level: "error",
|
|
164
|
-
message: message,
|
|
165
|
-
});
|
|
166
|
-
return 1;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
async function main() {
|
|
170
|
-
const exitCode = await runRepoRegisterCli(process.argv.slice(2));
|
|
171
|
-
process.exit(exitCode);
|
|
172
|
-
}
|
|
173
|
-
if (require.main === module) {
|
|
174
|
-
void main();
|
|
175
|
-
}
|
package/dist/repo-sync.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* repo-sync CLI command
|
|
4
|
-
*
|
|
5
|
-
* Syncs metadata for the current git repository with Spekn.
|
|
6
|
-
* Looks up the repo by its remote URL and updates name and default branch.
|
|
7
|
-
* Optionally runs AI analysis (same as repo register --analyze).
|
|
8
|
-
* Must be run from inside a local git clone.
|
|
9
|
-
*
|
|
10
|
-
* Usage: spekn repo sync --project-id <uuid> [--analyze] [--agent <name>] [--api-url <url>]
|
|
11
|
-
*/
|
|
12
|
-
import { type CommonOptions, type Deps } from "./repo-common";
|
|
13
|
-
declare function parseArgs(args: string[]): CommonOptions;
|
|
14
|
-
export declare function runRepoSyncCli(args: string[], deps?: Deps): Promise<number>;
|
|
15
|
-
declare function main(): Promise<void>;
|
|
16
|
-
export { main, parseArgs };
|