@hyperdrive.bot/gut 0.1.9 → 0.1.11

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 (35) hide show
  1. package/README.md +1048 -1
  2. package/dist/base-command.d.ts +2 -0
  3. package/dist/base-command.js +3 -0
  4. package/dist/commands/auth/login.d.ts +10 -0
  5. package/dist/commands/auth/login.js +103 -0
  6. package/dist/commands/auth/logout.d.ts +6 -0
  7. package/dist/commands/auth/logout.js +39 -0
  8. package/dist/commands/auth/status.d.ts +9 -0
  9. package/dist/commands/auth/status.js +87 -0
  10. package/dist/commands/entity/clone-all.d.ts +2 -1
  11. package/dist/commands/entity/clone-all.js +49 -10
  12. package/dist/commands/entity/clone.d.ts +3 -1
  13. package/dist/commands/entity/clone.js +45 -19
  14. package/dist/commands/ticket/config.d.ts +13 -0
  15. package/dist/commands/ticket/config.js +22 -0
  16. package/dist/commands/ticket/sync.d.ts +1 -0
  17. package/dist/commands/ticket/sync.js +62 -8
  18. package/dist/commands/worktree/create.d.ts +15 -0
  19. package/dist/commands/worktree/create.js +140 -0
  20. package/dist/models/entity.model.d.ts +16 -0
  21. package/dist/models/ticket.model.d.ts +2 -0
  22. package/dist/services/git.service.d.ts +11 -0
  23. package/dist/services/git.service.js +57 -0
  24. package/dist/services/git.service.test.d.ts +1 -0
  25. package/dist/services/git.service.test.js +101 -0
  26. package/dist/services/gut-api.service.d.ts +20 -1
  27. package/dist/services/gut-api.service.js +30 -2
  28. package/dist/services/tenant.service.d.ts +14 -0
  29. package/dist/services/tenant.service.js +24 -0
  30. package/dist/services/ticket.service.d.ts +3 -1
  31. package/dist/services/ticket.service.js +7 -3
  32. package/dist/services/worktree.service.d.ts +16 -0
  33. package/dist/services/worktree.service.js +60 -0
  34. package/oclif.manifest.json +231 -8
  35. package/package.json +16 -5
@@ -96,12 +96,16 @@ export class TicketService {
96
96
  /**
97
97
  * Sync ticket with external source
98
98
  */
99
- async syncTicket(ticketId, direction = 'push') {
99
+ async syncTicket(ticketId, direction = 'push', options) {
100
100
  if (this.useAuth && this.apiService) {
101
- return this.apiService.syncTicket(ticketId, direction);
101
+ return this.apiService.syncTicket(ticketId, direction, options);
102
102
  }
103
103
  // Fallback to unauthenticated mode
104
- const response = await this.makeFetchRequest('POST', `/gut/tickets/${encodeURIComponent(ticketId)}/sync?direction=${direction}`);
104
+ const params = new URLSearchParams({ direction });
105
+ if (options?.noEnrich) {
106
+ params.set('noEnrich', 'true');
107
+ }
108
+ const response = await this.makeFetchRequest('POST', `/gut/tickets/${encodeURIComponent(ticketId)}/sync?${params.toString()}`);
105
109
  return response;
106
110
  }
107
111
  /**
@@ -0,0 +1,16 @@
1
+ import type { WorktreeRecord, WorktreeState } from '../models/entity.model.js';
2
+ import type { ConfigService } from './config.service.js';
3
+ import type { FocusService } from './focus.service.js';
4
+ import type { GitService } from './git.service.js';
5
+ export declare class WorktreeService {
6
+ private readonly configService;
7
+ private readonly gitService;
8
+ private readonly focusService;
9
+ private readonly stateFile;
10
+ private readonly stateFileTmp;
11
+ constructor(configService: ConfigService, gitService: GitService, focusService: FocusService);
12
+ get(name: string): WorktreeRecord | null;
13
+ list(): WorktreeRecord[];
14
+ loadState(): WorktreeState;
15
+ saveState(state: WorktreeState): void;
16
+ }
@@ -0,0 +1,60 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ export class WorktreeService {
4
+ configService;
5
+ gitService;
6
+ focusService;
7
+ stateFile;
8
+ stateFileTmp;
9
+ constructor(configService, gitService, focusService) {
10
+ this.configService = configService;
11
+ this.gitService = gitService;
12
+ this.focusService = focusService;
13
+ this.stateFile = path.join(this.configService.getGutDir(), 'worktrees.json');
14
+ this.stateFileTmp = `${this.stateFile}.tmp`;
15
+ }
16
+ get(name) {
17
+ const state = this.loadState();
18
+ return state.worktrees.find(w => w.name === name) ?? null;
19
+ }
20
+ list() {
21
+ return this.loadState().worktrees;
22
+ }
23
+ loadState() {
24
+ if (!fs.existsSync(this.stateFile)) {
25
+ return { worktrees: [] };
26
+ }
27
+ try {
28
+ const content = fs.readFileSync(this.stateFile, 'utf-8');
29
+ const parsed = JSON.parse(content);
30
+ if (!Array.isArray(parsed.worktrees)) {
31
+ return { worktrees: [] };
32
+ }
33
+ return parsed;
34
+ }
35
+ catch {
36
+ console.warn('Corrupt worktrees.json, resetting state');
37
+ return { worktrees: [] };
38
+ }
39
+ }
40
+ saveState(state) {
41
+ const serialized = JSON.stringify(state, null, 2);
42
+ try {
43
+ fs.writeFileSync(this.stateFileTmp, serialized, 'utf-8');
44
+ fs.renameSync(this.stateFileTmp, this.stateFile);
45
+ }
46
+ catch (error) {
47
+ // Cleanup tmp file on failure
48
+ try {
49
+ if (fs.existsSync(this.stateFileTmp)) {
50
+ fs.unlinkSync(this.stateFileTmp);
51
+ }
52
+ }
53
+ catch {
54
+ // Ignore cleanup errors
55
+ }
56
+ const message = error instanceof Error ? error.message : String(error);
57
+ throw new Error(`Failed to save worktree state: ${message}`);
58
+ }
59
+ }
60
+ }
@@ -1302,6 +1302,107 @@
1302
1302
  "workspace.js"
1303
1303
  ]
1304
1304
  },
1305
+ "auth:login": {
1306
+ "aliases": [],
1307
+ "args": {},
1308
+ "description": "Authenticate with Gut using OAuth 2.0 PKCE flow",
1309
+ "examples": [
1310
+ "<%= config.bin %> <%= command.id %>",
1311
+ "<%= config.bin %> <%= command.id %> --domain acme.hyperdrive.bot",
1312
+ "<%= config.bin %> <%= command.id %> --port 9876"
1313
+ ],
1314
+ "flags": {
1315
+ "domain": {
1316
+ "char": "d",
1317
+ "description": "Tenant domain (e.g., acme.hyperdrive.bot)",
1318
+ "name": "domain",
1319
+ "hasDynamicHelp": false,
1320
+ "multiple": false,
1321
+ "type": "option"
1322
+ },
1323
+ "port": {
1324
+ "char": "p",
1325
+ "description": "Local callback server port",
1326
+ "name": "port",
1327
+ "default": 8766,
1328
+ "hasDynamicHelp": false,
1329
+ "multiple": false,
1330
+ "type": "option"
1331
+ }
1332
+ },
1333
+ "hasDynamicHelp": false,
1334
+ "hiddenAliases": [],
1335
+ "id": "auth:login",
1336
+ "pluginAlias": "@hyperdrive.bot/gut",
1337
+ "pluginName": "@hyperdrive.bot/gut",
1338
+ "pluginType": "core",
1339
+ "strict": true,
1340
+ "enableJsonFlag": false,
1341
+ "isESM": true,
1342
+ "relativePath": [
1343
+ "dist",
1344
+ "commands",
1345
+ "auth",
1346
+ "login.js"
1347
+ ]
1348
+ },
1349
+ "auth:logout": {
1350
+ "aliases": [],
1351
+ "args": {},
1352
+ "description": "Remove stored credentials and logout",
1353
+ "examples": [
1354
+ "<%= config.bin %> <%= command.id %>"
1355
+ ],
1356
+ "flags": {},
1357
+ "hasDynamicHelp": false,
1358
+ "hiddenAliases": [],
1359
+ "id": "auth:logout",
1360
+ "pluginAlias": "@hyperdrive.bot/gut",
1361
+ "pluginName": "@hyperdrive.bot/gut",
1362
+ "pluginType": "core",
1363
+ "strict": true,
1364
+ "enableJsonFlag": false,
1365
+ "isESM": true,
1366
+ "relativePath": [
1367
+ "dist",
1368
+ "commands",
1369
+ "auth",
1370
+ "logout.js"
1371
+ ]
1372
+ },
1373
+ "auth:status": {
1374
+ "aliases": [],
1375
+ "args": {},
1376
+ "description": "Show current authentication status",
1377
+ "examples": [
1378
+ "<%= config.bin %> <%= command.id %>",
1379
+ "<%= config.bin %> <%= command.id %> --verbose"
1380
+ ],
1381
+ "flags": {
1382
+ "verbose": {
1383
+ "char": "v",
1384
+ "description": "Show detailed credential information",
1385
+ "name": "verbose",
1386
+ "allowNo": false,
1387
+ "type": "boolean"
1388
+ }
1389
+ },
1390
+ "hasDynamicHelp": false,
1391
+ "hiddenAliases": [],
1392
+ "id": "auth:status",
1393
+ "pluginAlias": "@hyperdrive.bot/gut",
1394
+ "pluginName": "@hyperdrive.bot/gut",
1395
+ "pluginType": "core",
1396
+ "strict": true,
1397
+ "enableJsonFlag": false,
1398
+ "isESM": true,
1399
+ "relativePath": [
1400
+ "dist",
1401
+ "commands",
1402
+ "auth",
1403
+ "status.js"
1404
+ ]
1405
+ },
1305
1406
  "entity:add": {
1306
1407
  "aliases": [],
1307
1408
  "args": {
@@ -1394,9 +1495,8 @@
1394
1495
  "flags": {
1395
1496
  "branch": {
1396
1497
  "char": "b",
1397
- "description": "Branch to clone for all entities",
1498
+ "description": "Branch to clone for all entities (auto-detects workspace branch, falls back to master)",
1398
1499
  "name": "branch",
1399
- "default": "main",
1400
1500
  "hasDynamicHelp": false,
1401
1501
  "multiple": false,
1402
1502
  "type": "option"
@@ -1463,9 +1563,8 @@
1463
1563
  "flags": {
1464
1564
  "branch": {
1465
1565
  "char": "b",
1466
- "description": "Branch to clone",
1566
+ "description": "Branch to clone (auto-detects workspace branch, falls back to master)",
1467
1567
  "name": "branch",
1468
- "default": "main",
1469
1568
  "hasDynamicHelp": false,
1470
1569
  "multiple": false,
1471
1570
  "type": "option"
@@ -1605,6 +1704,70 @@
1605
1704
  "remove.js"
1606
1705
  ]
1607
1706
  },
1707
+ "ticket:config": {
1708
+ "aliases": [],
1709
+ "args": {},
1710
+ "description": "Configure ticket source (JIRA, GitHub, etc.) for this tenant",
1711
+ "examples": [
1712
+ "<%= config.bin %> ticket config --show",
1713
+ "<%= config.bin %> ticket config --type jira --url https://company.atlassian.net --secret-arn arn:aws:secretsmanager:..."
1714
+ ],
1715
+ "flags": {
1716
+ "secret-arn": {
1717
+ "description": "AWS Secrets Manager ARN for credentials",
1718
+ "name": "secret-arn",
1719
+ "hasDynamicHelp": false,
1720
+ "multiple": false,
1721
+ "type": "option"
1722
+ },
1723
+ "json": {
1724
+ "char": "j",
1725
+ "description": "output as JSON",
1726
+ "name": "json",
1727
+ "allowNo": false,
1728
+ "type": "boolean"
1729
+ },
1730
+ "show": {
1731
+ "description": "show current configuration",
1732
+ "name": "show",
1733
+ "allowNo": false,
1734
+ "type": "boolean"
1735
+ },
1736
+ "type": {
1737
+ "description": "source type",
1738
+ "name": "type",
1739
+ "hasDynamicHelp": false,
1740
+ "multiple": false,
1741
+ "options": [
1742
+ "jira",
1743
+ "github",
1744
+ "linear"
1745
+ ],
1746
+ "type": "option"
1747
+ },
1748
+ "url": {
1749
+ "description": "base URL (e.g., https://company.atlassian.net)",
1750
+ "name": "url",
1751
+ "hasDynamicHelp": false,
1752
+ "multiple": false,
1753
+ "type": "option"
1754
+ }
1755
+ },
1756
+ "hasDynamicHelp": false,
1757
+ "hiddenAliases": [],
1758
+ "id": "ticket:config",
1759
+ "pluginAlias": "@hyperdrive.bot/gut",
1760
+ "pluginName": "@hyperdrive.bot/gut",
1761
+ "pluginType": "core",
1762
+ "strict": true,
1763
+ "isESM": true,
1764
+ "relativePath": [
1765
+ "dist",
1766
+ "commands",
1767
+ "ticket",
1768
+ "config.js"
1769
+ ]
1770
+ },
1608
1771
  "ticket:focus": {
1609
1772
  "aliases": [],
1610
1773
  "args": {
@@ -1869,16 +2032,17 @@
1869
2032
  "aliases": [],
1870
2033
  "args": {
1871
2034
  "ticketId": {
1872
- "description": "ticket ID to sync",
2035
+ "description": "ticket ID to sync (e.g., PROJ-1234)",
1873
2036
  "name": "ticketId",
1874
2037
  "required": true
1875
2038
  }
1876
2039
  },
1877
- "description": "Sync ticket state with external source (JIRA, GitHub, etc.)",
2040
+ "description": "Sync ticket state with external source (JIRA, GitHub, etc.)\n\nFor pull direction:\n - If ticket exists in gut: updates from source\n - If ticket doesn't exist: creates it and queues enrichment\n\nFor push direction:\n - Updates source system with gut ticket state",
1878
2041
  "examples": [
1879
2042
  "<%= config.bin %> <%= command.id %> PROJ-1234",
1880
2043
  "<%= config.bin %> <%= command.id %> PROJ-1234 --direction push",
1881
- "<%= config.bin %> <%= command.id %> PROJ-1234 --direction pull"
2044
+ "<%= config.bin %> <%= command.id %> PROJ-1234 --direction pull",
2045
+ "<%= config.bin %> <%= command.id %> PROJ-1234 --direction pull --no-enrich"
1882
2046
  ],
1883
2047
  "flags": {
1884
2048
  "direction": {
@@ -1900,6 +2064,12 @@
1900
2064
  "name": "json",
1901
2065
  "allowNo": false,
1902
2066
  "type": "boolean"
2067
+ },
2068
+ "no-enrich": {
2069
+ "description": "skip enrichment queue when pulling new tickets",
2070
+ "name": "no-enrich",
2071
+ "allowNo": false,
2072
+ "type": "boolean"
1903
2073
  }
1904
2074
  },
1905
2075
  "hasDynamicHelp": false,
@@ -2002,7 +2172,60 @@
2002
2172
  "ticket",
2003
2173
  "update.js"
2004
2174
  ]
2175
+ },
2176
+ "worktree:create": {
2177
+ "aliases": [],
2178
+ "args": {
2179
+ "name": {
2180
+ "description": "Branch name for the worktree",
2181
+ "name": "name",
2182
+ "required": true
2183
+ }
2184
+ },
2185
+ "description": "Create mirrored worktrees for super-repo and focused entities",
2186
+ "examples": [
2187
+ "<%= config.bin %> worktree create workflow/deploy-batch",
2188
+ "<%= config.bin %> worktree create workflow/deploy-batch --from master --install",
2189
+ "<%= config.bin %> worktree create feature/story-42 --base-dir /home/user/worktrees"
2190
+ ],
2191
+ "flags": {
2192
+ "base-dir": {
2193
+ "description": "Root directory for worktrees",
2194
+ "name": "base-dir",
2195
+ "default": "/tmp/gut-worktrees",
2196
+ "hasDynamicHelp": false,
2197
+ "multiple": false,
2198
+ "type": "option"
2199
+ },
2200
+ "from": {
2201
+ "description": "Base branch to create from (defaults to current branch)",
2202
+ "name": "from",
2203
+ "hasDynamicHelp": false,
2204
+ "multiple": false,
2205
+ "type": "option"
2206
+ },
2207
+ "install": {
2208
+ "description": "Run pnpm install after creation",
2209
+ "name": "install",
2210
+ "allowNo": false,
2211
+ "type": "boolean"
2212
+ }
2213
+ },
2214
+ "hasDynamicHelp": false,
2215
+ "hiddenAliases": [],
2216
+ "id": "worktree:create",
2217
+ "pluginAlias": "@hyperdrive.bot/gut",
2218
+ "pluginName": "@hyperdrive.bot/gut",
2219
+ "pluginType": "core",
2220
+ "strict": true,
2221
+ "isESM": true,
2222
+ "relativePath": [
2223
+ "dist",
2224
+ "commands",
2225
+ "worktree",
2226
+ "create.js"
2227
+ ]
2005
2228
  }
2006
2229
  },
2007
- "version": "0.1.9"
2230
+ "version": "0.1.11"
2008
2231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperdrive.bot/gut",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "Git Unified Tooling - Enhanced git with workspace intelligence for entity-based organization",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,7 +11,8 @@
11
11
  "files": [
12
12
  "/bin",
13
13
  "/dist",
14
- "/oclif.manifest.json"
14
+ "/oclif.manifest.json",
15
+ "/templates"
15
16
  ],
16
17
  "scripts": {
17
18
  "build": "rm -rf dist && tsc -b",
@@ -19,7 +20,8 @@
19
20
  "lint": "eslint .",
20
21
  "postpack": "rm -f oclif.manifest.json",
21
22
  "prepack": "npm run build && npx oclif manifest || true",
22
- "test": "npm run build",
23
+ "test": "vitest run",
24
+ "test:unit": "vitest run",
23
25
  "version": "npx oclif readme && git add README.md || true"
24
26
  },
25
27
  "keywords": [
@@ -36,6 +38,7 @@
36
38
  },
37
39
  "dependencies": {
38
40
  "@hyperdrive.bot/cli-auth": "^1.1.1",
41
+ "@hyperdrive.bot/plugin-telemetry": "file:../telemetry-plugin",
39
42
  "@oclif/core": "^4.5.2",
40
43
  "@oclif/plugin-help": "^6.2.32",
41
44
  "axios": "^1.7.1",
@@ -56,14 +59,16 @@
56
59
  "eslint-config-oclif-typescript": "^3.1.14",
57
60
  "oclif": "^4.22.16",
58
61
  "ts-node": "^10.9.2",
59
- "typescript": "^5.9.2"
62
+ "typescript": "^5.9.2",
63
+ "vitest": "^4.1.0"
60
64
  },
61
65
  "oclif": {
62
66
  "bin": "gut",
63
67
  "dirname": "gut",
64
68
  "commands": "./dist/commands",
65
69
  "plugins": [
66
- "@oclif/plugin-help"
70
+ "@oclif/plugin-help",
71
+ "@hyperdrive.bot/plugin-telemetry"
67
72
  ],
68
73
  "topicSeparator": " ",
69
74
  "topics": {
@@ -75,6 +80,12 @@
75
80
  },
76
81
  "ticket": {
77
82
  "description": "Manage gut tickets from the ADHB system"
83
+ },
84
+ "claude": {
85
+ "description": "Claude Code integration"
86
+ },
87
+ "worktree": {
88
+ "description": "Manage entity-aware git worktrees for isolated pipeline runs"
78
89
  }
79
90
  }
80
91
  },