bobbi-agent 0.1.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 (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -0
  3. package/dist/auth.d.ts +65 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +152 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +245 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.d.ts +29 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +72 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/daemon.d.ts +17 -0
  16. package/dist/daemon.d.ts.map +1 -0
  17. package/dist/daemon.js +76 -0
  18. package/dist/daemon.js.map +1 -0
  19. package/dist/file-generator.d.ts +6 -0
  20. package/dist/file-generator.d.ts.map +1 -0
  21. package/dist/file-generator.js +129 -0
  22. package/dist/file-generator.js.map +1 -0
  23. package/dist/git-manager.d.ts +37 -0
  24. package/dist/git-manager.d.ts.map +1 -0
  25. package/dist/git-manager.js +135 -0
  26. package/dist/git-manager.js.map +1 -0
  27. package/dist/index.d.ts +6 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +5 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/sync-engine.d.ts +14 -0
  32. package/dist/sync-engine.d.ts.map +1 -0
  33. package/dist/sync-engine.js +97 -0
  34. package/dist/sync-engine.js.map +1 -0
  35. package/dist/types.d.ts +62 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +2 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/websocket-client.d.ts +48 -0
  40. package/dist/websocket-client.d.ts.map +1 -0
  41. package/dist/websocket-client.js +33 -0
  42. package/dist/websocket-client.js.map +1 -0
  43. package/package.json +66 -0
  44. package/templates/post-checkout +28 -0
  45. package/templates/post-commit +27 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # bobbi-agent
2
+
3
+ Local Bobbi Agent CLI daemon — syncs Sprint Planner with `./.bobbi/` for AI IDEs like Cursor.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install bobbi-agent
9
+ ```
10
+
11
+ Or globally:
12
+
13
+ ```bash
14
+ npm install -g bobbi-agent
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### CLI
20
+
21
+ ```bash
22
+ bobbi start # Start the sync daemon
23
+ bobbi login # Authenticate with Sprint Planner (device code)
24
+ bobbi hooks # Install git hooks (post-commit, post-checkout)
25
+ bobbi status # Show connection status
26
+ bobbi stop # Stop the daemon
27
+ ```
28
+
29
+ ### Programmatic API
30
+
31
+ ```typescript
32
+ import {
33
+ loadConfig,
34
+ loadState,
35
+ getValidAccessToken,
36
+ startSyncEngine,
37
+ stopSyncEngine,
38
+ runForeground,
39
+ spawnDaemon,
40
+ } from "bobbi-agent";
41
+ import type { Sprint, BobbiConfig, BobbiState } from "bobbi-agent";
42
+ ```
43
+
44
+ ## Configuration
45
+
46
+ Create `.bobbi/config.json` in your project (or run `bobbi login` to set it up):
47
+
48
+ ```json
49
+ {
50
+ "api_url": "https://your-sprint-planner.com",
51
+ "project_id": "your-project-id"
52
+ }
53
+ ```
54
+
55
+ Optional env vars:
56
+
57
+ - `BOBBI_API_URL` — Override API URL
58
+
59
+ ## Requirements
60
+
61
+ - Node.js >= 18
62
+ - Git repository
63
+
64
+ ## License
65
+
66
+ MIT
package/dist/auth.d.ts ADDED
@@ -0,0 +1,65 @@
1
+ import type { BobbiConfig } from "./types.js";
2
+ /**
3
+ * Device code response from POST /api/local-agent/auth/device-code
4
+ */
5
+ export interface DeviceCodeResponse {
6
+ device_code: string;
7
+ user_code: string;
8
+ verification_uri: string;
9
+ expires_in: number;
10
+ }
11
+ /**
12
+ * Token response from POST /api/local-agent/auth/token or refresh
13
+ */
14
+ export interface TokenResponse {
15
+ access_token: string;
16
+ refresh_token?: string;
17
+ expires_in: number;
18
+ }
19
+ /**
20
+ * Request a device code from the Sprint Planner API.
21
+ */
22
+ export declare function requestDeviceCode(apiUrl: string): Promise<DeviceCodeResponse>;
23
+ /**
24
+ * Exchange device code for tokens (poll until user completes login).
25
+ */
26
+ export declare function exchangeDeviceCode(apiUrl: string, deviceCode: string): Promise<TokenResponse>;
27
+ /**
28
+ * Refresh access token using refresh_token.
29
+ */
30
+ export declare function refreshAccessToken(apiUrl: string, refreshToken: string): Promise<TokenResponse>;
31
+ /**
32
+ * Get a valid access token: use cached if not expired, else refresh.
33
+ * Does not perform device-code flow; use login() for that.
34
+ */
35
+ export declare function getValidAccessToken(cwd?: string): Promise<string | null>;
36
+ /**
37
+ * Persist tokens into ./.bobbi/config.json after successful login.
38
+ */
39
+ export declare function saveTokens(cwd: string, config: BobbiConfig, tokens: TokenResponse): void;
40
+ /**
41
+ * Check if the given repo (owner/repo) is already linked to a project. Returns project_id and optional name or null.
42
+ */
43
+ export declare function repoMatch(apiUrl: string, accessToken: string, repo: string): Promise<{
44
+ project_id: string;
45
+ name?: string;
46
+ } | null>;
47
+ /**
48
+ * Create a connect-project request. Returns URL to open in browser and code for polling.
49
+ */
50
+ export declare function createConnectProject(apiUrl: string, accessToken: string): Promise<{
51
+ connect_code: string;
52
+ connect_url: string;
53
+ expires_in: number;
54
+ }>;
55
+ /**
56
+ * Poll connect-project status by code. Returns linked with project_id, or pending, or null if invalid/expired.
57
+ */
58
+ export declare function getConnectProjectStatus(apiUrl: string, code: string): Promise<{
59
+ status: "linked";
60
+ project_id: string;
61
+ } | {
62
+ status: "pending";
63
+ projects: unknown[];
64
+ } | null>;
65
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAYnF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,aAAa,CAAC,CAYxB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,aAAa,CAAC,CAYxB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2B9E;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,aAAa,GACpB,IAAI,CAYN;AAID;;GAEG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAYvD;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAe5E;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CASvG"}
package/dist/auth.js ADDED
@@ -0,0 +1,152 @@
1
+ import { writeFileSync, existsSync, mkdirSync } from "node:fs";
2
+ import { getBobbiDir, getConfigPath, loadConfig } from "./config.js";
3
+ const TOKEN_BUFFER_SECONDS = 60;
4
+ /**
5
+ * Request a device code from the Sprint Planner API.
6
+ */
7
+ export async function requestDeviceCode(apiUrl) {
8
+ const url = `${apiUrl.replace(/\/$/, "")}/api/local-agent/auth/device-code`;
9
+ const res = await fetch(url, {
10
+ method: "POST",
11
+ headers: { "Content-Type": "application/json" },
12
+ body: JSON.stringify({}),
13
+ });
14
+ if (!res.ok) {
15
+ const text = await res.text();
16
+ throw new Error(`Device code request failed: ${res.status} ${text}`);
17
+ }
18
+ return res.json();
19
+ }
20
+ /**
21
+ * Exchange device code for tokens (poll until user completes login).
22
+ */
23
+ export async function exchangeDeviceCode(apiUrl, deviceCode) {
24
+ const url = `${apiUrl.replace(/\/$/, "")}/api/local-agent/auth/token`;
25
+ const res = await fetch(url, {
26
+ method: "POST",
27
+ headers: { "Content-Type": "application/json" },
28
+ body: JSON.stringify({ device_code: deviceCode }),
29
+ });
30
+ if (!res.ok) {
31
+ const text = await res.text();
32
+ throw new Error(`Token exchange failed: ${res.status} ${text}`);
33
+ }
34
+ return res.json();
35
+ }
36
+ /**
37
+ * Refresh access token using refresh_token.
38
+ */
39
+ export async function refreshAccessToken(apiUrl, refreshToken) {
40
+ const url = `${apiUrl.replace(/\/$/, "")}/api/local-agent/auth/refresh`;
41
+ const res = await fetch(url, {
42
+ method: "POST",
43
+ headers: { "Content-Type": "application/json" },
44
+ body: JSON.stringify({ refresh_token: refreshToken }),
45
+ });
46
+ if (!res.ok) {
47
+ const text = await res.text();
48
+ throw new Error(`Token refresh failed: ${res.status} ${text}`);
49
+ }
50
+ return res.json();
51
+ }
52
+ /**
53
+ * Get a valid access token: use cached if not expired, else refresh.
54
+ * Does not perform device-code flow; use login() for that.
55
+ */
56
+ export async function getValidAccessToken(cwd) {
57
+ const config = loadConfig(cwd);
58
+ if (!config?.api_url)
59
+ return null;
60
+ const now = Math.floor(Date.now() / 1000);
61
+ if (config.access_token && (config.access_token_expires_at ?? 0) > now + TOKEN_BUFFER_SECONDS) {
62
+ return config.access_token;
63
+ }
64
+ if (!config.refresh_token)
65
+ return null;
66
+ try {
67
+ const tokenRes = await refreshAccessToken(config.api_url, config.refresh_token);
68
+ const dir = getBobbiDir(cwd);
69
+ const configPath = getConfigPath(cwd);
70
+ if (!existsSync(dir))
71
+ mkdirSync(dir, { recursive: true });
72
+ const updated = {
73
+ ...config,
74
+ access_token: tokenRes.access_token,
75
+ access_token_expires_at: now + tokenRes.expires_in,
76
+ refresh_token: tokenRes.refresh_token ?? config.refresh_token,
77
+ };
78
+ writeFileSync(configPath, JSON.stringify(updated, null, 2), "utf-8");
79
+ return tokenRes.access_token;
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ }
85
+ /**
86
+ * Persist tokens into ./.bobbi/config.json after successful login.
87
+ */
88
+ export function saveTokens(cwd, config, tokens) {
89
+ const dir = getBobbiDir(cwd);
90
+ const configPath = getConfigPath(cwd);
91
+ if (!existsSync(dir))
92
+ mkdirSync(dir, { recursive: true });
93
+ const now = Math.floor(Date.now() / 1000);
94
+ const updated = {
95
+ ...config,
96
+ access_token: tokens.access_token,
97
+ access_token_expires_at: now + tokens.expires_in,
98
+ refresh_token: tokens.refresh_token ?? config.refresh_token,
99
+ };
100
+ writeFileSync(configPath, JSON.stringify(updated, null, 2), "utf-8");
101
+ }
102
+ const base = (apiUrl) => apiUrl.replace(/\/$/, "");
103
+ /**
104
+ * Check if the given repo (owner/repo) is already linked to a project. Returns project_id and optional name or null.
105
+ */
106
+ export async function repoMatch(apiUrl, accessToken, repo) {
107
+ const url = `${base(apiUrl)}/api/local-agent/repo-match?repo=${encodeURIComponent(repo)}`;
108
+ const res = await fetch(url, {
109
+ headers: { Authorization: `Bearer ${accessToken}` },
110
+ });
111
+ if (res.status === 404)
112
+ return null;
113
+ if (!res.ok) {
114
+ const text = await res.text();
115
+ throw new Error(`Repo match failed: ${res.status} ${text}`);
116
+ }
117
+ const data = (await res.json());
118
+ return { project_id: data.project_id, name: data.name };
119
+ }
120
+ /**
121
+ * Create a connect-project request. Returns URL to open in browser and code for polling.
122
+ */
123
+ export async function createConnectProject(apiUrl, accessToken) {
124
+ const url = `${base(apiUrl)}/api/local-agent/connect-project`;
125
+ const res = await fetch(url, {
126
+ method: "POST",
127
+ headers: {
128
+ "Content-Type": "application/json",
129
+ Authorization: `Bearer ${accessToken}`,
130
+ },
131
+ body: JSON.stringify({}),
132
+ });
133
+ if (!res.ok) {
134
+ const text = await res.text();
135
+ throw new Error(`Connect project failed: ${res.status} ${text}`);
136
+ }
137
+ return res.json();
138
+ }
139
+ /**
140
+ * Poll connect-project status by code. Returns linked with project_id, or pending, or null if invalid/expired.
141
+ */
142
+ export async function getConnectProjectStatus(apiUrl, code) {
143
+ const url = `${base(apiUrl)}/api/local-agent/connect-project?code=${encodeURIComponent(code)}`;
144
+ const res = await fetch(url);
145
+ if (res.status === 404)
146
+ return null;
147
+ if (!res.ok)
148
+ return null;
149
+ const data = (await res.json());
150
+ return data;
151
+ }
152
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,245 @@
1
+ #!/usr/bin/env node
2
+ import { config as loadEnv } from "dotenv";
3
+ import { Command } from "commander";
4
+ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { dirname } from "node:path";
8
+ import { getBobbiDir, getConfigPath, getStatePath, getTasksDir, getLogsDir, loadConfig, loadState, getDefaultConfig, } from "./config.js";
9
+ import { installHooks, getOriginRepoSlug } from "./git-manager.js";
10
+ import { runForeground, spawnDaemon } from "./daemon.js";
11
+ import { requestDeviceCode, exchangeDeviceCode, saveTokens, getValidAccessToken, repoMatch, createConnectProject, getConnectProjectStatus, } from "./auth.js";
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ // Load .env from package root (bobbi-agent/.env) so BOBBI_API_URL works for "npm run login"
14
+ loadEnv({ path: join(__dirname, "..", ".env") });
15
+ const templatesDir = join(__dirname, "..", "templates");
16
+ const program = new Command();
17
+ program
18
+ .name("bobbi")
19
+ .description("Local Bobbi Agent — sync Sprint Planner with ./.bobbi/ for AI IDEs")
20
+ .version("0.1.0");
21
+ program
22
+ .command("login")
23
+ .description("Authenticate with Sprint Planner (device code)")
24
+ .option("--api-url <url>", "Sprint Planner URL (e.g. http://localhost:3000)")
25
+ .action(async (opts) => {
26
+ const cwd = process.cwd();
27
+ const defaultCfg = getDefaultConfig();
28
+ const apiUrl = opts.apiUrl ??
29
+ process.env.BOBBI_API_URL ??
30
+ defaultCfg.api_url ??
31
+ "https://yourapp.com";
32
+ console.log("Requesting device code from", apiUrl, "...");
33
+ const { device_code, user_code, expires_in } = await requestDeviceCode(apiUrl);
34
+ const openUrl = `${apiUrl.replace(/\/$/, "")}/auth/device`;
35
+ console.log(`\n1. Open: ${openUrl}`);
36
+ console.log(`2. Enter code: ${user_code}`);
37
+ console.log(`3. Code expires in ${expires_in}s. Waiting for you to complete login...\n`);
38
+ let tokens;
39
+ const start = Date.now();
40
+ while (Date.now() - start < expires_in * 1000) {
41
+ await new Promise((r) => setTimeout(r, 3000));
42
+ try {
43
+ tokens = await exchangeDeviceCode(apiUrl, device_code);
44
+ break;
45
+ }
46
+ catch {
47
+ process.stdout.write(".");
48
+ continue;
49
+ }
50
+ }
51
+ if (!tokens) {
52
+ console.error("\nLogin timed out. Run 'bobbi login' again.");
53
+ process.exit(1);
54
+ }
55
+ const bobbiDir = getBobbiDir(cwd);
56
+ if (!existsSync(bobbiDir))
57
+ mkdirSync(bobbiDir, { recursive: true });
58
+ const configPath = getConfigPath(cwd);
59
+ let config = {
60
+ project_id: "",
61
+ api_url: apiUrl,
62
+ environment: defaultCfg.environment ?? "production",
63
+ auto_start: defaultCfg.auto_start ?? true,
64
+ };
65
+ if (existsSync(configPath)) {
66
+ try {
67
+ const raw = readFileSync(configPath, "utf-8");
68
+ config = { ...config, ...JSON.parse(raw) };
69
+ }
70
+ catch {
71
+ // use defaults
72
+ }
73
+ }
74
+ saveTokens(cwd, config, tokens);
75
+ console.log("\nLogin successful. Run 'bobbi init' to link a project.");
76
+ });
77
+ program
78
+ .command("init")
79
+ .description("Link repo to Sprint Planner, create ./.bobbi/, install hooks, start daemon")
80
+ .option("--project-id <id>", "Sprint Planner project ID")
81
+ .option("--api-url <url>", "Sprint Planner API base URL")
82
+ .action(async (opts) => {
83
+ const cwd = process.cwd();
84
+ const git = await import("./git-manager.js").then((m) => m.getGit(cwd));
85
+ try {
86
+ await git.status();
87
+ }
88
+ catch {
89
+ console.error("Not a git repository. Run 'git init' first.");
90
+ process.exit(1);
91
+ }
92
+ let config;
93
+ const bobbiDir = getBobbiDir(cwd);
94
+ const configPath = getConfigPath(cwd);
95
+ if (existsSync(configPath)) {
96
+ const raw = readFileSync(configPath, "utf-8");
97
+ config = JSON.parse(raw);
98
+ }
99
+ else {
100
+ const defaults = getDefaultConfig();
101
+ config = {
102
+ project_id: opts.projectId ?? "",
103
+ api_url: opts.apiUrl ?? defaults.api_url ?? "https://yourapp.com",
104
+ environment: defaults.environment ?? "production",
105
+ auto_start: defaults.auto_start ?? true,
106
+ };
107
+ }
108
+ if (opts.projectId)
109
+ config.project_id = opts.projectId;
110
+ if (opts.apiUrl)
111
+ config.api_url = opts.apiUrl;
112
+ if (!config.project_id) {
113
+ const apiUrl = config.api_url;
114
+ const token = await getValidAccessToken(cwd);
115
+ if (!token) {
116
+ console.error("Run 'bobbi login' first, then 'bobbi init'.");
117
+ process.exit(1);
118
+ }
119
+ const repoSlug = await getOriginRepoSlug(cwd);
120
+ if (repoSlug) {
121
+ try {
122
+ const match = await repoMatch(apiUrl, token, repoSlug);
123
+ if (match) {
124
+ config.project_id = match.project_id;
125
+ const namePart = match.name ? ` (${match.name})` : "";
126
+ console.log(`Repo matched to project${namePart}. Linking...`);
127
+ }
128
+ }
129
+ catch {
130
+ // fall through to connect-project flow
131
+ }
132
+ }
133
+ if (!config.project_id) {
134
+ try {
135
+ const { connect_url, connect_code, expires_in } = await createConnectProject(apiUrl, token);
136
+ console.log(`\nOpen this URL to link a project (expires in ${Math.floor(expires_in / 60)} min):\n ${connect_url}\n`);
137
+ try {
138
+ const { execa } = await import("execa");
139
+ const cmd = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
140
+ await execa(cmd, [connect_url], { detached: true }).catch(() => { });
141
+ }
142
+ catch {
143
+ // ignore if open fails
144
+ }
145
+ console.log("Waiting for you to select a project in the browser...");
146
+ const deadline = Date.now() + expires_in * 1000;
147
+ while (Date.now() < deadline) {
148
+ await new Promise((r) => setTimeout(r, 2500));
149
+ const status = await getConnectProjectStatus(apiUrl, connect_code);
150
+ if (status?.status === "linked" && status.project_id) {
151
+ config.project_id = status.project_id;
152
+ process.stdout.write("\n");
153
+ console.log("Project linked.");
154
+ break;
155
+ }
156
+ if (status === null) {
157
+ console.error("Link expired or invalid. Run 'bobbi init' again.");
158
+ process.exit(1);
159
+ }
160
+ process.stdout.write(".");
161
+ }
162
+ if (!config.project_id) {
163
+ console.error("\nTimed out. Run 'bobbi init' again or use: bobbi init --project-id <uuid>");
164
+ process.exit(1);
165
+ }
166
+ }
167
+ catch (err) {
168
+ console.error(err instanceof Error ? err.message : "Failed to start link flow.");
169
+ process.exit(1);
170
+ }
171
+ }
172
+ }
173
+ if (!config.project_id) {
174
+ console.error("Project ID required. Run: bobbi init --project-id <uuid>");
175
+ process.exit(1);
176
+ }
177
+ if (!existsSync(bobbiDir))
178
+ mkdirSync(bobbiDir, { recursive: true });
179
+ mkdirSync(getTasksDir(cwd), { recursive: true });
180
+ mkdirSync(getLogsDir(cwd), { recursive: true });
181
+ writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
182
+ const statePath = getStatePath(cwd);
183
+ if (!existsSync(statePath)) {
184
+ writeFileSync(statePath, JSON.stringify({
185
+ last_sync_time: new Date().toISOString(),
186
+ last_commit_hash: "",
187
+ active_branch: "main",
188
+ sprint_version: "",
189
+ }, null, 2), "utf-8");
190
+ }
191
+ installHooks(cwd, templatesDir);
192
+ const token = await getValidAccessToken(cwd);
193
+ if (!token) {
194
+ console.log("Run 'bobbi login' to authenticate, then 'bobbi start'.");
195
+ }
196
+ else if (config.auto_start) {
197
+ spawnDaemon(cwd);
198
+ console.log("Daemon started. ./.bobbi/ is ready.");
199
+ }
200
+ else {
201
+ console.log("Run 'bobbi start' to start the daemon.");
202
+ }
203
+ });
204
+ program
205
+ .command("start")
206
+ .description("Start the agent (foreground or daemon)")
207
+ .option("--background", "Spawn as background daemon")
208
+ .action((opts) => {
209
+ const cwd = process.cwd();
210
+ if (opts.background) {
211
+ spawnDaemon(cwd);
212
+ console.log("Daemon started.");
213
+ return;
214
+ }
215
+ runForeground(cwd);
216
+ });
217
+ program
218
+ .command("stop")
219
+ .description("Stop the daemon")
220
+ .action(() => {
221
+ // Without PID file we can't kill; user can Ctrl+C or kill process by name
222
+ console.log("If the daemon is running in another terminal, stop it with Ctrl+C.");
223
+ console.log("Or run: pkill -f 'bobbi start'");
224
+ });
225
+ program
226
+ .command("status")
227
+ .description("Show connection and sprint status")
228
+ .action(async () => {
229
+ const cwd = process.cwd();
230
+ const config = loadConfig(cwd);
231
+ const state = loadState(cwd);
232
+ if (!config) {
233
+ console.log("Not initialized. Run 'bobbi init'.");
234
+ return;
235
+ }
236
+ const token = await getValidAccessToken(cwd);
237
+ console.log("Connected:", !!token);
238
+ console.log("Project ID:", config.project_id ?? "(not set)");
239
+ console.log("API URL:", config.api_url);
240
+ console.log("Branch:", state?.active_branch ?? "—");
241
+ console.log("Last sync:", state?.last_sync_time ?? "—");
242
+ console.log("Sprint version:", state?.sprint_version ?? "—");
243
+ });
244
+ program.parse();
245
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { BobbiConfig, BobbiState } from "./types.js";
2
+ declare const DEFAULT_API_URL = "https://yourapp.com";
3
+ declare const BOBBI_DIR = ".bobbi";
4
+ declare const CONFIG_FILE = "config.json";
5
+ declare const STATE_FILE = "state.json";
6
+ /**
7
+ * Resolve ./.bobbi directory (from cwd when running in a repo).
8
+ */
9
+ export declare function getBobbiDir(cwd?: string): string;
10
+ export declare function getConfigPath(cwd?: string): string;
11
+ export declare function getStatePath(cwd?: string): string;
12
+ export declare function getTasksDir(cwd?: string): string;
13
+ export declare function getLogsDir(cwd?: string): string;
14
+ export declare function getSprintPath(cwd?: string): string;
15
+ export declare function getContextPath(cwd?: string): string;
16
+ /**
17
+ * Load config from ./.bobbi/config.json. Returns null if not initialized.
18
+ */
19
+ export declare function loadConfig(cwd?: string): BobbiConfig | null;
20
+ /**
21
+ * Load state from ./.bobbi/state.json. Returns null if missing.
22
+ */
23
+ export declare function loadState(cwd?: string): BobbiState | null;
24
+ /**
25
+ * Default config for init (before project_id and api_url are set).
26
+ */
27
+ export declare function getDefaultConfig(): Partial<BobbiConfig>;
28
+ export { BOBBI_DIR, CONFIG_FILE, STATE_FILE, DEFAULT_API_URL };
29
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D,QAAA,MAAM,eAAe,wBAAwB,CAAC;AAC9C,QAAA,MAAM,SAAS,WAAW,CAAC;AAC3B,QAAA,MAAM,WAAW,gBAAgB,CAAC;AAClC,QAAA,MAAM,UAAU,eAAe,CAAC;AAEhC;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAE/D;AAED,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,cAAc,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAS3D;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CASzD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,WAAW,CAAC,CAMvD;AAED,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC"}