@sascha384/tic 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 (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +221 -0
  3. package/dist/app.d.ts +17 -0
  4. package/dist/app.js +27 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/backends/factory.d.ts +5 -0
  7. package/dist/backends/factory.js +42 -0
  8. package/dist/backends/factory.js.map +1 -0
  9. package/dist/backends/github/gh.d.ts +2 -0
  10. package/dist/backends/github/gh.js +17 -0
  11. package/dist/backends/github/gh.js.map +1 -0
  12. package/dist/backends/github/index.d.ts +26 -0
  13. package/dist/backends/github/index.js +188 -0
  14. package/dist/backends/github/index.js.map +1 -0
  15. package/dist/backends/github/mappers.d.ts +33 -0
  16. package/dist/backends/github/mappers.js +26 -0
  17. package/dist/backends/github/mappers.js.map +1 -0
  18. package/dist/backends/gitlab/glab.d.ts +2 -0
  19. package/dist/backends/gitlab/glab.js +17 -0
  20. package/dist/backends/gitlab/glab.js.map +1 -0
  21. package/dist/backends/gitlab/group.d.ts +1 -0
  22. package/dist/backends/gitlab/group.js +33 -0
  23. package/dist/backends/gitlab/group.js.map +1 -0
  24. package/dist/backends/gitlab/index.d.ts +29 -0
  25. package/dist/backends/gitlab/index.js +296 -0
  26. package/dist/backends/gitlab/index.js.map +1 -0
  27. package/dist/backends/gitlab/mappers.d.ts +43 -0
  28. package/dist/backends/gitlab/mappers.js +44 -0
  29. package/dist/backends/gitlab/mappers.js.map +1 -0
  30. package/dist/backends/local/config.d.ts +12 -0
  31. package/dist/backends/local/config.js +28 -0
  32. package/dist/backends/local/config.js.map +1 -0
  33. package/dist/backends/local/index.d.ts +26 -0
  34. package/dist/backends/local/index.js +212 -0
  35. package/dist/backends/local/index.js.map +1 -0
  36. package/dist/backends/local/items.d.ts +6 -0
  37. package/dist/backends/local/items.js +118 -0
  38. package/dist/backends/local/items.js.map +1 -0
  39. package/dist/backends/types.d.ts +56 -0
  40. package/dist/backends/types.js +39 -0
  41. package/dist/backends/types.js.map +1 -0
  42. package/dist/cli/commands/config.d.ts +2 -0
  43. package/dist/cli/commands/config.js +40 -0
  44. package/dist/cli/commands/config.js.map +1 -0
  45. package/dist/cli/commands/init.d.ts +6 -0
  46. package/dist/cli/commands/init.js +12 -0
  47. package/dist/cli/commands/init.js.map +1 -0
  48. package/dist/cli/commands/item.d.ts +41 -0
  49. package/dist/cli/commands/item.js +80 -0
  50. package/dist/cli/commands/item.js.map +1 -0
  51. package/dist/cli/commands/iteration.d.ts +7 -0
  52. package/dist/cli/commands/iteration.js +10 -0
  53. package/dist/cli/commands/iteration.js.map +1 -0
  54. package/dist/cli/commands/mcp.d.ts +85 -0
  55. package/dist/cli/commands/mcp.js +448 -0
  56. package/dist/cli/commands/mcp.js.map +1 -0
  57. package/dist/cli/format.d.ts +3 -0
  58. package/dist/cli/format.js +10 -0
  59. package/dist/cli/format.js.map +1 -0
  60. package/dist/cli/index.d.ts +4 -0
  61. package/dist/cli/index.js +426 -0
  62. package/dist/cli/index.js.map +1 -0
  63. package/dist/components/IterationPicker.d.ts +1 -0
  64. package/dist/components/IterationPicker.js +18 -0
  65. package/dist/components/IterationPicker.js.map +1 -0
  66. package/dist/components/Settings.d.ts +1 -0
  67. package/dist/components/Settings.js +40 -0
  68. package/dist/components/Settings.js.map +1 -0
  69. package/dist/components/WorkItemForm.d.ts +1 -0
  70. package/dist/components/WorkItemForm.js +270 -0
  71. package/dist/components/WorkItemForm.js.map +1 -0
  72. package/dist/components/WorkItemList.d.ts +1 -0
  73. package/dist/components/WorkItemList.js +219 -0
  74. package/dist/components/WorkItemList.js.map +1 -0
  75. package/dist/git.d.ts +38 -0
  76. package/dist/git.js +115 -0
  77. package/dist/git.js.map +1 -0
  78. package/dist/implement.d.ts +25 -0
  79. package/dist/implement.js +130 -0
  80. package/dist/implement.js.map +1 -0
  81. package/dist/index.d.ts +2 -0
  82. package/dist/index.js +14 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/types.d.ts +26 -0
  85. package/dist/types.js +2 -0
  86. package/dist/types.js.map +1 -0
  87. package/package.json +66 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 fa-krug
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,221 @@
1
+ # tic
2
+
3
+ A terminal UI for issue tracking, built for developers who live in the terminal. Track work items as markdown files stored right in your repository.
4
+
5
+ Built with TypeScript and [Ink](https://github.com/vadimdemedes/ink).
6
+
7
+ ## Features
8
+
9
+ - **Keyboard-driven TUI** — browse, create, edit, and manage work items without leaving the terminal
10
+ - **Local markdown storage** — work items stored as markdown files with YAML frontmatter in a `.tic/` directory
11
+ - **Work item types** — organize by epic, issue, and task (configurable)
12
+ - **Iterations** — group work into sprints or milestones
13
+ - **Parent-child relationships** — build hierarchies with tree-indented views
14
+ - **Dependencies** — track which items block others, with warnings on premature completion
15
+ - **Priority & assignee** — track who owns what and what's most important
16
+ - **Comments** — add timestamped comments to any work item
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install -g tic
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```bash
27
+ cd your-project
28
+ tic
29
+ ```
30
+
31
+ This launches the TUI. On first run, tic automatically creates a `.tic/` directory to store your work items. No setup or init command needed.
32
+
33
+ ## Usage
34
+
35
+ ### List View
36
+
37
+ The main screen shows work items filtered by type and iteration, displayed as a tree that reflects parent-child relationships.
38
+
39
+ | Key | Action |
40
+ |-----|--------|
41
+ | `↑` `↓` | Navigate between items |
42
+ | `Enter` | Edit selected item |
43
+ | `c` | Create new work item |
44
+ | `d` | Delete selected item (with confirmation) |
45
+ | `s` | Cycle status forward |
46
+ | `p` | Set parent for selected item |
47
+ | `Tab` | Switch work item type (epic / issue / task) |
48
+ | `i` | Switch iteration |
49
+ | `q` | Quit |
50
+
51
+ The list displays ID, title (tree-indented), status, priority, and assignee. Items with dependencies show a `⧗` indicator.
52
+
53
+ ### Editing a Work Item
54
+
55
+ Press `Enter` on an item or `c` to create one. The form has these fields:
56
+
57
+ - **Title** — name of the work item
58
+ - **Type** — epic, issue, or task
59
+ - **Status** — backlog, todo, in-progress, review, done
60
+ - **Iteration** — which sprint/milestone this belongs to
61
+ - **Priority** — low, medium, high, critical
62
+ - **Assignee** — who owns this
63
+ - **Labels** — comma-separated tags
64
+ - **Parent** — ID of the parent item
65
+ - **Depends On** — comma-separated IDs of items this depends on
66
+ - **Description** — full details (multi-line)
67
+ - **Comments** — add new comments; existing comments shown as read-only
68
+
69
+ Navigate fields with `↑` `↓`, press `Enter` to edit a field, and `Esc` to save and return to the list.
70
+
71
+ ### Iterations
72
+
73
+ Press `i` in the list view to open the iteration picker. The current iteration filters which items you see. New iterations are created automatically when you assign an item to one that doesn't exist yet.
74
+
75
+ ### Relationships
76
+
77
+ **Parent-child:** Set a parent ID on an item to nest it under another. Children appear indented in the tree view. Circular parent chains are prevented.
78
+
79
+ **Dependencies:** Add dependency IDs to indicate that an item is blocked by others. When you try to complete an item that has open children or unresolved dependencies, tic shows a warning so you can decide whether to proceed.
80
+
81
+ Deleting an item automatically cleans up references — children have their parent cleared, and the item is removed from other items' dependency lists.
82
+
83
+ ## Storage
84
+
85
+ Work items live in `.tic/` at the root of your project:
86
+
87
+ ```
88
+ .tic/
89
+ ├── config.yml # Types, statuses, iterations, settings
90
+ └── items/
91
+ ├── 1.md # Work item #1
92
+ ├── 2.md # Work item #2
93
+ └── ...
94
+ ```
95
+
96
+ Each item is a markdown file with YAML frontmatter:
97
+
98
+ ```markdown
99
+ ---
100
+ id: 1
101
+ title: Implement user login
102
+ type: task
103
+ status: in-progress
104
+ iteration: sprint-1
105
+ priority: high
106
+ assignee: alice
107
+ labels: auth, backend
108
+ parent: 3
109
+ depends_on:
110
+ - 2
111
+ created: 2026-01-15T10:00:00.000Z
112
+ updated: 2026-01-20T14:30:00.000Z
113
+ ---
114
+
115
+ Full description of the work item goes here.
116
+
117
+ ## Comments
118
+
119
+ ---
120
+ author: alice
121
+ date: 2026-01-18T09:00:00.000Z
122
+
123
+ Decided to use JWT tokens for this.
124
+ ```
125
+
126
+ Configuration in `.tic/config.yml`:
127
+
128
+ ```yaml
129
+ types:
130
+ - epic
131
+ - issue
132
+ - task
133
+ statuses:
134
+ - backlog
135
+ - todo
136
+ - in-progress
137
+ - review
138
+ - done
139
+ iterations:
140
+ - default
141
+ current_iteration: default
142
+ next_id: 1
143
+ ```
144
+
145
+ You can edit these files directly — they're plain text. Customize types, statuses, and iterations by editing `config.yml`.
146
+
147
+ ## MCP Server
148
+
149
+ tic includes a built-in [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server that exposes your work items to AI assistants like Claude. This lets AI tools read, create, update, and manage your issues without leaving the conversation.
150
+
151
+ ### Starting the Server
152
+
153
+ ```bash
154
+ tic mcp serve
155
+ ```
156
+
157
+ The server communicates over stdio using the MCP protocol.
158
+
159
+ ### Connecting to Claude Code
160
+
161
+ Add tic as an MCP server in your project:
162
+
163
+ ```bash
164
+ claude mcp add --scope project --transport stdio tic -- npx tic mcp serve
165
+ ```
166
+
167
+ Or create a `.mcp.json` file in your project root:
168
+
169
+ ```json
170
+ {
171
+ "mcpServers": {
172
+ "tic": {
173
+ "type": "stdio",
174
+ "command": "npx",
175
+ "args": ["tic", "mcp", "serve"]
176
+ }
177
+ }
178
+ }
179
+ ```
180
+
181
+ ### Available Tools
182
+
183
+ The MCP server exposes 14 tools:
184
+
185
+ | Tool | Description |
186
+ |------|-------------|
187
+ | `init_project` | Initialize a new tic project (creates `.tic/` directory) |
188
+ | `get_config` | Get project configuration (statuses, types, iterations) |
189
+ | `list_items` | List work items with optional filters by type, status, or iteration |
190
+ | `show_item` | Show full details of a single work item |
191
+ | `create_item` | Create a new work item with title, type, status, priority, and more |
192
+ | `update_item` | Update any field on an existing work item |
193
+ | `delete_item` | Preview deleting a work item (shows affected children and dependents) |
194
+ | `confirm_delete` | Confirm and execute a previously previewed deletion |
195
+ | `add_comment` | Add a timestamped comment to a work item |
196
+ | `set_iteration` | Set the current active iteration |
197
+ | `search_items` | Search work items by text query across titles and descriptions |
198
+ | `get_children` | Get child items of a specific work item |
199
+ | `get_dependents` | Get items that depend on a specific work item |
200
+ | `get_item_tree` | Get work items as a hierarchical tree structure |
201
+
202
+ ### Safety
203
+
204
+ Deletion is a two-step process: `delete_item` returns a preview of what will be affected (children that will be unparented, dependents that will lose a dependency), and `confirm_delete` must be called separately to actually remove the item. This prevents accidental data loss when AI tools are managing your issues.
205
+
206
+ If the server is started in a directory without a `.tic/` project, all tools except `init_project` will return an error asking you to initialize first.
207
+
208
+ ## Roadmap
209
+
210
+ Planned but not yet implemented:
211
+
212
+ - **Multi-backend support** — GitHub (via `gh`), GitLab (via `glab`), Azure DevOps (via `az`)
213
+ - **Automatic backend detection** — select backend based on git remote
214
+
215
+ ## Contributing
216
+
217
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, architecture, and conventions.
218
+
219
+ ## License
220
+
221
+ [MIT](LICENSE)
package/dist/app.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type { Backend } from './backends/types.js';
2
+ type Screen = 'list' | 'form' | 'iteration-picker' | 'settings';
3
+ interface AppState {
4
+ screen: Screen;
5
+ selectedWorkItemId: string | null;
6
+ activeType: string | null;
7
+ backend: Backend;
8
+ navigate: (screen: Screen) => void;
9
+ selectWorkItem: (id: string | null) => void;
10
+ setActiveType: (type: string | null) => void;
11
+ }
12
+ export declare const AppContext: import("react").Context<AppState>;
13
+ export declare function useAppState(): AppState;
14
+ export declare function App({ backend }: {
15
+ backend: Backend;
16
+ }): import("react/jsx-runtime").JSX.Element;
17
+ export {};
package/dist/app.js ADDED
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, createContext, useContext } from 'react';
3
+ import { Box } from 'ink';
4
+ import { WorkItemList } from './components/WorkItemList.js';
5
+ import { WorkItemForm } from './components/WorkItemForm.js';
6
+ import { IterationPicker } from './components/IterationPicker.js';
7
+ import { Settings } from './components/Settings.js';
8
+ export const AppContext = createContext(null);
9
+ export function useAppState() {
10
+ return useContext(AppContext);
11
+ }
12
+ export function App({ backend }) {
13
+ const [screen, setScreen] = useState('list');
14
+ const [selectedWorkItemId, setSelectedWorkItemId] = useState(null);
15
+ const [activeType, setActiveType] = useState(null);
16
+ const state = {
17
+ screen,
18
+ selectedWorkItemId,
19
+ activeType,
20
+ backend,
21
+ navigate: setScreen,
22
+ selectWorkItem: setSelectedWorkItemId,
23
+ setActiveType,
24
+ };
25
+ return (_jsx(AppContext.Provider, { value: state, children: _jsxs(Box, { flexDirection: "column", children: [screen === 'list' && _jsx(WorkItemList, {}), screen === 'form' && _jsx(WorkItemForm, {}), screen === 'iteration-picker' && _jsx(IterationPicker, {}), screen === 'settings' && _jsx(Settings, {})] }) }));
26
+ }
27
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAepD,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAW,IAAK,CAAC,CAAC;AAEzD,MAAM,UAAU,WAAW;IACzB,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,EAAE,OAAO,EAAwB;IACnD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAS,MAAM,CAAC,CAAC;IACrD,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAC1D,IAAI,CACL,CAAC;IACF,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAElE,MAAM,KAAK,GAAa;QACtB,MAAM;QACN,kBAAkB;QAClB,UAAU;QACV,OAAO;QACP,QAAQ,EAAE,SAAS;QACnB,cAAc,EAAE,qBAAqB;QACrC,aAAa;KACd,CAAC;IAEF,OAAO,CACL,KAAC,UAAU,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAC/B,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,aACxB,MAAM,KAAK,MAAM,IAAI,KAAC,YAAY,KAAG,EACrC,MAAM,KAAK,MAAM,IAAI,KAAC,YAAY,KAAG,EACrC,MAAM,KAAK,kBAAkB,IAAI,KAAC,eAAe,KAAG,EACpD,MAAM,KAAK,UAAU,IAAI,KAAC,QAAQ,KAAG,IAClC,GACc,CACvB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Backend } from './types.js';
2
+ export declare const VALID_BACKENDS: readonly ["local", "github", "gitlab", "azure"];
3
+ export type BackendType = (typeof VALID_BACKENDS)[number];
4
+ export declare function detectBackend(root: string): BackendType;
5
+ export declare function createBackend(root: string): Backend;
@@ -0,0 +1,42 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { LocalBackend } from './local/index.js';
3
+ import { GitHubBackend } from './github/index.js';
4
+ import { GitLabBackend } from './gitlab/index.js';
5
+ import { readConfig } from './local/config.js';
6
+ export const VALID_BACKENDS = ['local', 'github', 'gitlab', 'azure'];
7
+ export function detectBackend(root) {
8
+ try {
9
+ const output = execSync('git remote -v', {
10
+ cwd: root,
11
+ encoding: 'utf-8',
12
+ stdio: ['pipe', 'pipe', 'pipe'],
13
+ });
14
+ if (output.includes('github.com'))
15
+ return 'github';
16
+ if (output.includes('gitlab.com'))
17
+ return 'gitlab';
18
+ if (output.includes('dev.azure.com'))
19
+ return 'azure';
20
+ }
21
+ catch {
22
+ // Not a git repo or git not available
23
+ }
24
+ return 'local';
25
+ }
26
+ export function createBackend(root) {
27
+ const config = readConfig(root);
28
+ const backend = config.backend ?? 'local';
29
+ switch (backend) {
30
+ case 'local':
31
+ return new LocalBackend(root);
32
+ case 'github':
33
+ return new GitHubBackend(root);
34
+ case 'gitlab':
35
+ return new GitLabBackend(root);
36
+ case 'azure':
37
+ throw new Error(`Backend "${backend}" is not yet implemented. Use "local" for now.`);
38
+ default:
39
+ throw new Error(`Unknown backend "${backend}". Valid backends: ${VALID_BACKENDS.join(', ')}`);
40
+ }
41
+ }
42
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/backends/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAU,CAAC;AAG9E,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,eAAe,EAAE;YACvC,GAAG,EAAE,IAAI;YACT,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,OAAO,QAAQ,CAAC;QACnD,IAAI,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,OAAO,QAAQ,CAAC;QACnD,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC;YAAE,OAAO,OAAO,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,sCAAsC;IACxC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,OAAO,CAAC;IAE1C,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,OAAO;YACV,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;QAChC,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,CAAC;QACjC,KAAK,OAAO;YACV,MAAM,IAAI,KAAK,CACb,YAAY,OAAO,gDAAgD,CACpE,CAAC;QACJ;YACE,MAAM,IAAI,KAAK,CACb,oBAAoB,OAAO,sBAAsB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7E,CAAC;IACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function gh<T>(args: string[], cwd: string): T;
2
+ export declare function ghExec(args: string[], cwd: string): string;
@@ -0,0 +1,17 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ export function gh(args, cwd) {
3
+ const result = execFileSync('gh', args, {
4
+ cwd,
5
+ encoding: 'utf-8',
6
+ stdio: ['pipe', 'pipe', 'pipe'],
7
+ });
8
+ return JSON.parse(result);
9
+ }
10
+ export function ghExec(args, cwd) {
11
+ return execFileSync('gh', args, {
12
+ cwd,
13
+ encoding: 'utf-8',
14
+ stdio: ['pipe', 'pipe', 'pipe'],
15
+ });
16
+ }
17
+ //# sourceMappingURL=gh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gh.js","sourceRoot":"","sources":["../../../src/backends/github/gh.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,UAAU,EAAE,CAAI,IAAc,EAAE,GAAW;IAC/C,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE;QACtC,GAAG;QACH,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAChC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAM,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAc,EAAE,GAAW;IAChD,OAAO,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE;QAC9B,GAAG;QACH,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;KAChC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { BaseBackend } from '../types.js';
2
+ import type { BackendCapabilities } from '../types.js';
3
+ import type { WorkItem, NewWorkItem, NewComment, Comment } from '../../types.js';
4
+ export declare class GitHubBackend extends BaseBackend {
5
+ private cwd;
6
+ constructor(cwd: string);
7
+ getCapabilities(): BackendCapabilities;
8
+ getStatuses(): string[];
9
+ getWorkItemTypes(): string[];
10
+ getIterations(): string[];
11
+ getCurrentIteration(): string;
12
+ setCurrentIteration(_name: string): void;
13
+ listWorkItems(iteration?: string): WorkItem[];
14
+ getWorkItem(id: string): WorkItem;
15
+ createWorkItem(data: NewWorkItem): WorkItem;
16
+ updateWorkItem(id: string, data: Partial<WorkItem>): WorkItem;
17
+ deleteWorkItem(id: string): void;
18
+ addComment(workItemId: string, comment: NewComment): Comment;
19
+ getChildren(id: string): WorkItem[];
20
+ getDependents(id: string): WorkItem[];
21
+ getItemUrl(id: string): string;
22
+ openItem(id: string): void;
23
+ private fetchMilestones;
24
+ private fetchOpenMilestones;
25
+ private getRepoNwo;
26
+ }
@@ -0,0 +1,188 @@
1
+ import { BaseBackend } from '../types.js';
2
+ import { gh, ghExec } from './gh.js';
3
+ import { mapIssueToWorkItem } from './mappers.js';
4
+ const ISSUE_FIELDS = 'number,title,body,state,assignees,labels,milestone,createdAt,updatedAt,comments';
5
+ export class GitHubBackend extends BaseBackend {
6
+ cwd;
7
+ constructor(cwd) {
8
+ super();
9
+ this.cwd = cwd;
10
+ ghExec(['auth', 'status'], cwd);
11
+ }
12
+ getCapabilities() {
13
+ return {
14
+ relationships: false,
15
+ customTypes: false,
16
+ customStatuses: false,
17
+ iterations: true,
18
+ comments: true,
19
+ fields: {
20
+ priority: false,
21
+ assignee: true,
22
+ labels: true,
23
+ parent: false,
24
+ dependsOn: false,
25
+ },
26
+ };
27
+ }
28
+ getStatuses() {
29
+ return ['open', 'closed'];
30
+ }
31
+ getWorkItemTypes() {
32
+ return ['issue'];
33
+ }
34
+ getIterations() {
35
+ const milestones = this.fetchMilestones();
36
+ return milestones.map((m) => m.title);
37
+ }
38
+ getCurrentIteration() {
39
+ const milestones = this.fetchOpenMilestones();
40
+ if (milestones.length === 0)
41
+ return '';
42
+ return milestones[0].title;
43
+ }
44
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
45
+ setCurrentIteration(_name) {
46
+ // No-op — current iteration is always first open milestone
47
+ }
48
+ listWorkItems(iteration) {
49
+ const args = [
50
+ 'issue',
51
+ 'list',
52
+ '--state',
53
+ 'all',
54
+ '--json',
55
+ ISSUE_FIELDS,
56
+ '--limit',
57
+ '500',
58
+ ];
59
+ if (iteration) {
60
+ args.push('--milestone', iteration);
61
+ }
62
+ const issues = gh(args, this.cwd);
63
+ return issues.map(mapIssueToWorkItem);
64
+ }
65
+ getWorkItem(id) {
66
+ const issue = gh(['issue', 'view', id, '--json', ISSUE_FIELDS], this.cwd);
67
+ return mapIssueToWorkItem(issue);
68
+ }
69
+ createWorkItem(data) {
70
+ this.validateFields(data);
71
+ const args = ['issue', 'create', '--title', data.title];
72
+ if (data.description) {
73
+ args.push('--body', data.description);
74
+ }
75
+ if (data.assignee) {
76
+ args.push('--assignee', data.assignee);
77
+ }
78
+ if (data.iteration) {
79
+ args.push('--milestone', data.iteration);
80
+ }
81
+ for (const label of data.labels) {
82
+ args.push('--label', label);
83
+ }
84
+ const output = ghExec(args, this.cwd);
85
+ // gh issue create prints the URL: https://github.com/owner/repo/issues/123
86
+ const match = output.match(/\/issues\/(\d+)/);
87
+ if (!match) {
88
+ throw new Error('Failed to parse issue number from gh output');
89
+ }
90
+ const id = match[1];
91
+ return this.getWorkItem(id);
92
+ }
93
+ updateWorkItem(id, data) {
94
+ this.validateFields(data);
95
+ // Handle status changes via close/reopen
96
+ if (data.status === 'closed') {
97
+ ghExec(['issue', 'close', id], this.cwd);
98
+ }
99
+ else if (data.status === 'open') {
100
+ ghExec(['issue', 'reopen', id], this.cwd);
101
+ }
102
+ // Handle field edits
103
+ const editArgs = ['issue', 'edit', id];
104
+ let hasEdits = false;
105
+ if (data.title !== undefined) {
106
+ editArgs.push('--title', data.title);
107
+ hasEdits = true;
108
+ }
109
+ if (data.description !== undefined) {
110
+ editArgs.push('--body', data.description);
111
+ hasEdits = true;
112
+ }
113
+ if (data.iteration !== undefined) {
114
+ if (data.iteration) {
115
+ editArgs.push('--milestone', data.iteration);
116
+ }
117
+ else {
118
+ editArgs.push('--remove-milestone');
119
+ }
120
+ hasEdits = true;
121
+ }
122
+ if (data.assignee !== undefined) {
123
+ if (data.assignee) {
124
+ editArgs.push('--add-assignee', data.assignee);
125
+ }
126
+ hasEdits = true;
127
+ }
128
+ if (data.labels !== undefined) {
129
+ for (const label of data.labels) {
130
+ editArgs.push('--add-label', label);
131
+ }
132
+ hasEdits = true;
133
+ }
134
+ if (hasEdits) {
135
+ ghExec(editArgs, this.cwd);
136
+ }
137
+ return this.getWorkItem(id);
138
+ }
139
+ deleteWorkItem(id) {
140
+ ghExec(['issue', 'delete', id, '--yes'], this.cwd);
141
+ }
142
+ addComment(workItemId, comment) {
143
+ ghExec(['issue', 'comment', workItemId, '--body', comment.body], this.cwd);
144
+ return {
145
+ author: comment.author,
146
+ date: new Date().toISOString(),
147
+ body: comment.body,
148
+ };
149
+ }
150
+ getChildren(id) {
151
+ this.assertSupported(this.getCapabilities().relationships, 'relationships');
152
+ return this.listWorkItems().filter((item) => item.parent === id);
153
+ }
154
+ getDependents(id) {
155
+ this.assertSupported(this.getCapabilities().relationships, 'relationships');
156
+ return this.listWorkItems().filter((item) => item.dependsOn.includes(id));
157
+ }
158
+ getItemUrl(id) {
159
+ const result = gh(['issue', 'view', id, '--json', 'url'], this.cwd);
160
+ return result.url;
161
+ }
162
+ openItem(id) {
163
+ ghExec(['issue', 'view', id, '--web'], this.cwd);
164
+ }
165
+ fetchMilestones() {
166
+ const owner = this.getRepoNwo();
167
+ return gh(['api', `repos/${owner}/milestones`, '--jq', '.'], this.cwd);
168
+ }
169
+ fetchOpenMilestones() {
170
+ const milestones = this.fetchMilestones();
171
+ return milestones
172
+ .filter((m) => m.state === 'open')
173
+ .sort((a, b) => {
174
+ if (!a.due_on && !b.due_on)
175
+ return 0;
176
+ if (!a.due_on)
177
+ return 1;
178
+ if (!b.due_on)
179
+ return -1;
180
+ return a.due_on.localeCompare(b.due_on);
181
+ });
182
+ }
183
+ getRepoNwo() {
184
+ const result = gh(['repo', 'view', '--json', 'nameWithOwner'], this.cwd);
185
+ return result.nameWithOwner;
186
+ }
187
+ }
188
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/backends/github/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { WorkItem, Comment } from '../../types.js';
2
+ export interface GhIssue {
3
+ number: number;
4
+ title: string;
5
+ body: string | null;
6
+ state: string;
7
+ assignees: {
8
+ login: string;
9
+ }[];
10
+ labels: {
11
+ name: string;
12
+ }[];
13
+ milestone: {
14
+ title: string;
15
+ } | null;
16
+ createdAt: string;
17
+ updatedAt: string;
18
+ comments?: GhComment[];
19
+ }
20
+ export interface GhComment {
21
+ author: {
22
+ login: string;
23
+ };
24
+ createdAt: string;
25
+ body: string;
26
+ }
27
+ export interface GhMilestone {
28
+ title: string;
29
+ state: string;
30
+ due_on: string | null;
31
+ }
32
+ export declare function mapCommentToComment(ghComment: GhComment): Comment;
33
+ export declare function mapIssueToWorkItem(ghIssue: GhIssue): WorkItem;
@@ -0,0 +1,26 @@
1
+ export function mapCommentToComment(ghComment) {
2
+ return {
3
+ author: ghComment.author.login,
4
+ date: ghComment.createdAt,
5
+ body: ghComment.body,
6
+ };
7
+ }
8
+ export function mapIssueToWorkItem(ghIssue) {
9
+ return {
10
+ id: String(ghIssue.number),
11
+ title: ghIssue.title,
12
+ description: ghIssue.body ?? '',
13
+ status: ghIssue.state === 'OPEN' ? 'open' : 'closed',
14
+ type: 'issue',
15
+ assignee: ghIssue.assignees[0]?.login ?? '',
16
+ labels: ghIssue.labels.map((l) => l.name),
17
+ iteration: ghIssue.milestone?.title ?? '',
18
+ priority: 'medium',
19
+ created: ghIssue.createdAt,
20
+ updated: ghIssue.updatedAt,
21
+ parent: null,
22
+ dependsOn: [],
23
+ comments: (ghIssue.comments ?? []).map(mapCommentToComment),
24
+ };
25
+ }
26
+ //# sourceMappingURL=mappers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mappers.js","sourceRoot":"","sources":["../../../src/backends/github/mappers.ts"],"names":[],"mappings":"AA2BA,MAAM,UAAU,mBAAmB,CAAC,SAAoB;IACtD,OAAO;QACL,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,KAAK;QAC9B,IAAI,EAAE,SAAS,CAAC,SAAS;QACzB,IAAI,EAAE,SAAS,CAAC,IAAI;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,WAAW,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE;QAC/B,MAAM,EAAE,OAAO,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;QACpD,IAAI,EAAE,OAAO;QACb,QAAQ,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACzC,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QACzC,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,OAAO,CAAC,SAAS;QAC1B,OAAO,EAAE,OAAO,CAAC,SAAS;QAC1B,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC;KAC5D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function glab<T>(args: string[], cwd: string): T;
2
+ export declare function glabExec(args: string[], cwd: string): string;