argustack 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.
- package/LICENSE +21 -0
- package/README.md +433 -0
- package/dist/adapters/csv/index.d.ts +4 -0
- package/dist/adapters/csv/index.d.ts.map +1 -0
- package/dist/adapters/csv/index.js +4 -0
- package/dist/adapters/csv/index.js.map +1 -0
- package/dist/adapters/csv/mapper.d.ts +10 -0
- package/dist/adapters/csv/mapper.d.ts.map +1 -0
- package/dist/adapters/csv/mapper.js +179 -0
- package/dist/adapters/csv/mapper.js.map +1 -0
- package/dist/adapters/csv/parser.d.ts +22 -0
- package/dist/adapters/csv/parser.d.ts.map +1 -0
- package/dist/adapters/csv/parser.js +96 -0
- package/dist/adapters/csv/parser.js.map +1 -0
- package/dist/adapters/csv/provider.d.ts +11 -0
- package/dist/adapters/csv/provider.d.ts.map +1 -0
- package/dist/adapters/csv/provider.js +98 -0
- package/dist/adapters/csv/provider.js.map +1 -0
- package/dist/adapters/git/index.d.ts +3 -0
- package/dist/adapters/git/index.d.ts.map +1 -0
- package/dist/adapters/git/index.js +3 -0
- package/dist/adapters/git/index.js.map +1 -0
- package/dist/adapters/git/mapper.d.ts +11 -0
- package/dist/adapters/git/mapper.d.ts.map +1 -0
- package/dist/adapters/git/mapper.js +47 -0
- package/dist/adapters/git/mapper.js.map +1 -0
- package/dist/adapters/git/provider.d.ts +12 -0
- package/dist/adapters/git/provider.d.ts.map +1 -0
- package/dist/adapters/git/provider.js +115 -0
- package/dist/adapters/git/provider.js.map +1 -0
- package/dist/adapters/github/client.d.ts +8 -0
- package/dist/adapters/github/client.d.ts.map +1 -0
- package/dist/adapters/github/client.js +5 -0
- package/dist/adapters/github/client.js.map +1 -0
- package/dist/adapters/github/index.d.ts +4 -0
- package/dist/adapters/github/index.d.ts.map +1 -0
- package/dist/adapters/github/index.js +4 -0
- package/dist/adapters/github/index.js.map +1 -0
- package/dist/adapters/github/mapper.d.ts +12 -0
- package/dist/adapters/github/mapper.d.ts.map +1 -0
- package/dist/adapters/github/mapper.js +117 -0
- package/dist/adapters/github/mapper.js.map +1 -0
- package/dist/adapters/github/provider.d.ts +18 -0
- package/dist/adapters/github/provider.d.ts.map +1 -0
- package/dist/adapters/github/provider.js +95 -0
- package/dist/adapters/github/provider.js.map +1 -0
- package/dist/adapters/jira/client.d.ts +11 -0
- package/dist/adapters/jira/client.d.ts.map +1 -0
- package/dist/adapters/jira/client.js +16 -0
- package/dist/adapters/jira/client.js.map +1 -0
- package/dist/adapters/jira/index.d.ts +3 -0
- package/dist/adapters/jira/index.d.ts.map +1 -0
- package/dist/adapters/jira/index.js +3 -0
- package/dist/adapters/jira/index.js.map +1 -0
- package/dist/adapters/jira/mapper.d.ts +14 -0
- package/dist/adapters/jira/mapper.d.ts.map +1 -0
- package/dist/adapters/jira/mapper.js +169 -0
- package/dist/adapters/jira/mapper.js.map +1 -0
- package/dist/adapters/jira/provider.d.ts +21 -0
- package/dist/adapters/jira/provider.d.ts.map +1 -0
- package/dist/adapters/jira/provider.js +79 -0
- package/dist/adapters/jira/provider.js.map +1 -0
- package/dist/adapters/openai/embedding-provider.d.ts +16 -0
- package/dist/adapters/openai/embedding-provider.d.ts.map +1 -0
- package/dist/adapters/openai/embedding-provider.js +34 -0
- package/dist/adapters/openai/embedding-provider.js.map +1 -0
- package/dist/adapters/openai/index.d.ts +2 -0
- package/dist/adapters/openai/index.d.ts.map +1 -0
- package/dist/adapters/openai/index.js +2 -0
- package/dist/adapters/openai/index.js.map +1 -0
- package/dist/adapters/postgres/connection.d.ts +13 -0
- package/dist/adapters/postgres/connection.d.ts.map +1 -0
- package/dist/adapters/postgres/connection.js +16 -0
- package/dist/adapters/postgres/connection.js.map +1 -0
- package/dist/adapters/postgres/index.d.ts +3 -0
- package/dist/adapters/postgres/index.d.ts.map +1 -0
- package/dist/adapters/postgres/index.js +3 -0
- package/dist/adapters/postgres/index.js.map +1 -0
- package/dist/adapters/postgres/schema.d.ts +6 -0
- package/dist/adapters/postgres/schema.d.ts.map +1 -0
- package/dist/adapters/postgres/schema.js +246 -0
- package/dist/adapters/postgres/schema.js.map +1 -0
- package/dist/adapters/postgres/storage.d.ts +32 -0
- package/dist/adapters/postgres/storage.d.ts.map +1 -0
- package/dist/adapters/postgres/storage.js +322 -0
- package/dist/adapters/postgres/storage.js.map +1 -0
- package/dist/cli/embed.d.ts +3 -0
- package/dist/cli/embed.d.ts.map +1 -0
- package/dist/cli/embed.js +52 -0
- package/dist/cli/embed.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +64 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +24 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +966 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/jira.d.ts +3 -0
- package/dist/cli/jira.d.ts.map +1 -0
- package/dist/cli/jira.js +78 -0
- package/dist/cli/jira.js.map +1 -0
- package/dist/cli/mcp-install.d.ts +10 -0
- package/dist/cli/mcp-install.d.ts.map +1 -0
- package/dist/cli/mcp-install.js +207 -0
- package/dist/cli/mcp-install.js.map +1 -0
- package/dist/cli/sources.d.ts +10 -0
- package/dist/cli/sources.d.ts.map +1 -0
- package/dist/cli/sources.js +132 -0
- package/dist/cli/sources.js.map +1 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +93 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/sync.d.ts +21 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +321 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/core/ports/embedding-provider.d.ts +15 -0
- package/dist/core/ports/embedding-provider.d.ts.map +1 -0
- package/dist/core/ports/embedding-provider.js +2 -0
- package/dist/core/ports/embedding-provider.js.map +1 -0
- package/dist/core/ports/git-provider.d.ts +30 -0
- package/dist/core/ports/git-provider.d.ts.map +1 -0
- package/dist/core/ports/git-provider.js +2 -0
- package/dist/core/ports/git-provider.js.map +1 -0
- package/dist/core/ports/github-provider.d.ts +30 -0
- package/dist/core/ports/github-provider.d.ts.map +1 -0
- package/dist/core/ports/github-provider.js +2 -0
- package/dist/core/ports/github-provider.js.map +1 -0
- package/dist/core/ports/index.d.ts +6 -0
- package/dist/core/ports/index.d.ts.map +1 -0
- package/dist/core/ports/index.js +2 -0
- package/dist/core/ports/index.js.map +1 -0
- package/dist/core/ports/source-provider.d.ts +27 -0
- package/dist/core/ports/source-provider.d.ts.map +1 -0
- package/dist/core/ports/source-provider.js +2 -0
- package/dist/core/ports/source-provider.js.map +1 -0
- package/dist/core/ports/storage.d.ts +47 -0
- package/dist/core/ports/storage.d.ts.map +1 -0
- package/dist/core/ports/storage.js +2 -0
- package/dist/core/ports/storage.js.map +1 -0
- package/dist/core/types/config.d.ts +26 -0
- package/dist/core/types/config.d.ts.map +1 -0
- package/dist/core/types/config.js +41 -0
- package/dist/core/types/config.js.map +1 -0
- package/dist/core/types/git.d.ts +35 -0
- package/dist/core/types/git.d.ts.map +1 -0
- package/dist/core/types/git.js +6 -0
- package/dist/core/types/git.js.map +1 -0
- package/dist/core/types/github.d.ts +75 -0
- package/dist/core/types/github.d.ts.map +1 -0
- package/dist/core/types/github.js +2 -0
- package/dist/core/types/github.js.map +1 -0
- package/dist/core/types/index.d.ts +7 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/core/types/index.js +2 -0
- package/dist/core/types/index.js.map +1 -0
- package/dist/core/types/issue.d.ts +74 -0
- package/dist/core/types/issue.d.ts.map +1 -0
- package/dist/core/types/issue.js +7 -0
- package/dist/core/types/issue.js.map +1 -0
- package/dist/core/types/project.d.ts +9 -0
- package/dist/core/types/project.d.ts.map +1 -0
- package/dist/core/types/project.js +5 -0
- package/dist/core/types/project.js.map +1 -0
- package/dist/db/connection.d.ts +2 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +4 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/import.d.ts +2 -0
- package/dist/db/import.d.ts.map +1 -0
- package/dist/db/import.js +4 -0
- package/dist/db/import.js.map +1 -0
- package/dist/db/schema.d.ts +2 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +4 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/jira/client.d.ts +2 -0
- package/dist/jira/client.d.ts.map +1 -0
- package/dist/jira/client.js +4 -0
- package/dist/jira/client.js.map +1 -0
- package/dist/jira/pull.d.ts +2 -0
- package/dist/jira/pull.d.ts.map +1 -0
- package/dist/jira/pull.js +5 -0
- package/dist/jira/pull.js.map +1 -0
- package/dist/mcp/server.d.ts +16 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +1463 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/use-cases/embed.d.ts +23 -0
- package/dist/use-cases/embed.d.ts.map +1 -0
- package/dist/use-cases/embed.js +63 -0
- package/dist/use-cases/embed.js.map +1 -0
- package/dist/use-cases/pull-git.d.ts +25 -0
- package/dist/use-cases/pull-git.d.ts.map +1 -0
- package/dist/use-cases/pull-git.js +59 -0
- package/dist/use-cases/pull-git.js.map +1 -0
- package/dist/use-cases/pull-github.d.ts +28 -0
- package/dist/use-cases/pull-github.d.ts.map +1 -0
- package/dist/use-cases/pull-github.js +67 -0
- package/dist/use-cases/pull-github.js.map +1 -0
- package/dist/use-cases/pull.d.ts +32 -0
- package/dist/use-cases/pull.d.ts.map +1 -0
- package/dist/use-cases/pull.js +82 -0
- package/dist/use-cases/pull.js.map +1 -0
- package/dist/workspace/config.d.ts +36 -0
- package/dist/workspace/config.d.ts.map +1 -0
- package/dist/workspace/config.js +91 -0
- package/dist/workspace/config.js.map +1 -0
- package/dist/workspace/resolver.d.ts +19 -0
- package/dist/workspace/resolver.d.ts.map +1 -0
- package/dist/workspace/resolver.js +47 -0
- package/dist/workspace/resolver.js.map +1 -0
- package/package.json +71 -0
- package/templates/docker-compose.yml +26 -0
- package/templates/env.example +14 -0
- package/templates/gitignore +6 -0
- package/templates/init.sql +236 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ievgen
|
|
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,433 @@
|
|
|
1
|
+
# Argustack
|
|
2
|
+
|
|
3
|
+
**RAG engine for project intelligence — ask AI about your Jira, Git, and databases**
|
|
4
|
+
|
|
5
|
+
[RAG](https://en.wikipedia.org/wiki/Retrieval-augmented_generation) (Retrieval-Augmented Generation) — an architecture where AI answers questions based on **your** data, not its training set:
|
|
6
|
+
|
|
7
|
+
1. **Retrieval** — pull and index your project data locally (PostgreSQL + pgvector)
|
|
8
|
+
2. **Augmentation** — inject relevant context into the AI prompt
|
|
9
|
+
3. **Generation** — LLM generates answers grounded in your actual Jira tickets, code, and databases
|
|
10
|
+
|
|
11
|
+
Argustack builds this knowledge base from your project's sources of truth:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
YOUR SOURCES YOUR MACHINE
|
|
15
|
+
┌──────────────────────┐ ┌─────────────────────────────────────┐
|
|
16
|
+
│ Jira Cloud / Server │ │ │
|
|
17
|
+
│ (issues, comments, │ pull │ PostgreSQL (Docker, localhost) │
|
|
18
|
+
│ changelogs, etc.) │ ──────►│ ├── issues (all fields) │
|
|
19
|
+
└──────────────────────┘ │ ├── issue_comments (discussions) │
|
|
20
|
+
│ ├── issue_changelogs (history) │
|
|
21
|
+
┌──────────────────────┐ │ ├── issue_worklogs (time logs) │
|
|
22
|
+
│ Git repository │ pull │ ├── issue_links (relations) │
|
|
23
|
+
│ (commits, files, │ ──────►│ ├── commits (history) │
|
|
24
|
+
│ diffs, authors) │ │ ├── commit_files (per-file Δ) │
|
|
25
|
+
└──────────────────────┘ │ ├── commit_issue_refs (cross-ref)│
|
|
26
|
+
│ │ │
|
|
27
|
+
┌──────────────────────┐ │ │ GitHub (optional, via token) │
|
|
28
|
+
│ GitHub API │ pull │ ├── pull_requests (PRs + meta) │
|
|
29
|
+
│ (PRs, reviews, │ ──────►│ ├── pr_reviews (approvals) │
|
|
30
|
+
│ releases) │ │ ├── pr_comments (discussions) │
|
|
31
|
+
└──────────────────────┘ │ ├── pr_issue_refs (PR↔Jira) │
|
|
32
|
+
│ └── releases (tags) │
|
|
33
|
+
┌──────────────────────┐ │ │
|
|
34
|
+
│ Database (planned) │ │ MCP Server (localhost, stdio) │
|
|
35
|
+
└──────────────────────┘ │ └── queries DB ──► Claude / LLM │
|
|
36
|
+
│ │
|
|
37
|
+
│ .env (credentials — never leaves) │
|
|
38
|
+
└─────────────────────────────────────┘
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
> *Is this bug still relevant or already fixed in code?*
|
|
42
|
+
> *Was the feature implemented as described in the ticket?*
|
|
43
|
+
> *Who worked on this module and what changed last month?*
|
|
44
|
+
> *Which commits and PRs reference ticket PAP-123?*
|
|
45
|
+
> *Who approved the PR and what was the review feedback?*
|
|
46
|
+
|
|
47
|
+
## How it works
|
|
48
|
+
|
|
49
|
+
**Retrieval** — pulls all data from Jira, Git, and GitHub into local PostgreSQL with pgvector. Every field, every comment, every changelog entry, every commit with per-file diffs, every PR with reviews and approvals. Raw JSON preserved as-is. Nothing is filtered or lost.
|
|
50
|
+
|
|
51
|
+
**Augmentation** — MCP server gives Claude Desktop / Claude Code direct access to your local database. Full-text search, semantic search (pgvector embeddings), filters, raw SQL, aggregate statistics, cross-source timeline, cross-reference between Jira issues, Git commits, and GitHub PRs — all without leaving your machine.
|
|
52
|
+
|
|
53
|
+
**Generation** — ask questions in natural language. Claude queries your local data and answers with full project context.
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
### Prerequisites
|
|
58
|
+
|
|
59
|
+
- [Node.js](https://nodejs.org/) >= 20
|
|
60
|
+
- [Docker](https://www.docker.com/) (or [OrbStack](https://orbstack.dev/) / Podman)
|
|
61
|
+
|
|
62
|
+
### Install & setup
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm i -g argustack
|
|
66
|
+
argustack init
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Argustack supports **two modes** of initialization:
|
|
70
|
+
|
|
71
|
+
#### Interactive mode (default)
|
|
72
|
+
|
|
73
|
+
Run `argustack init` and follow the prompts:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
? Workspace directory: ~/projects/my-team
|
|
77
|
+
? Sources: ✔ Jira — issues, comments, changelogs
|
|
78
|
+
✔ Git — commits, diffs, authors
|
|
79
|
+
✔ GitHub — PRs, reviews, releases
|
|
80
|
+
? Jira URL: https://your-team.atlassian.net
|
|
81
|
+
? Email: you@company.com
|
|
82
|
+
? API Token: ****
|
|
83
|
+
|
|
84
|
+
Testing connection... Connected! Found 3 projects: MKT, BRAND, WEB
|
|
85
|
+
|
|
86
|
+
? Projects to pull: ✔ MKT ✔ BRAND
|
|
87
|
+
? Where is your Git repository?
|
|
88
|
+
● Clone from GitHub — select repos using your token
|
|
89
|
+
? GitHub token (PAT): ****
|
|
90
|
+
|
|
91
|
+
Fetching repositories... Found 12 repos.
|
|
92
|
+
|
|
93
|
+
? Repositories to clone: ✔ your-org/frontend ✔ your-org/backend
|
|
94
|
+
? GitHub source: Auto-configured from clone step
|
|
95
|
+
|
|
96
|
+
? Start database and sync now? Yes
|
|
97
|
+
|
|
98
|
+
✔ Database running!
|
|
99
|
+
✔ Jira sync complete!
|
|
100
|
+
MKT: 506 issues (150/506 ████░░░░ 30% → 506/506 done)
|
|
101
|
+
✔ Git sync complete!
|
|
102
|
+
your-org/frontend: 735 commits (400/735 ██████░░ 54% → 735/735 done)
|
|
103
|
+
✔ GitHub sync complete!
|
|
104
|
+
66 PRs (30/66 ██████░░ 45% → 66/66 done), 124 reviews, 3 releases
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The interactive setup will:
|
|
108
|
+
|
|
109
|
+
1. Ask which sources you have (Jira, Git, GitHub, Database)
|
|
110
|
+
2. Collect credentials and test connections
|
|
111
|
+
3. For Git — choose local path, clone from GitHub (multi-select repos), or clone from URL
|
|
112
|
+
4. For GitHub — auto-configured if you cloned from GitHub in the previous step, or enter a Personal Access Token (see [GitHub token setup](#github-token-setup))
|
|
113
|
+
5. Create a workspace with Docker config
|
|
114
|
+
6. Start PostgreSQL + pgweb automatically
|
|
115
|
+
7. Pull all your data
|
|
116
|
+
|
|
117
|
+
#### Non-interactive mode (for AI agents and CI/CD)
|
|
118
|
+
|
|
119
|
+
Pass `--no-interactive` with all values as CLI flags — no prompts, no terminal needed:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
argustack init \
|
|
123
|
+
--no-interactive \
|
|
124
|
+
--dir ~/projects/my-team \
|
|
125
|
+
--source jira,git,github \
|
|
126
|
+
--jira-url "https://your-team.atlassian.net" \
|
|
127
|
+
--jira-email "you@company.com" \
|
|
128
|
+
--jira-token "ATATT3x..." \
|
|
129
|
+
--jira-projects PAP,MKT \
|
|
130
|
+
--git-repo /path/to/repo1,/path/to/repo2 \
|
|
131
|
+
--github-token "github_pat_..." \
|
|
132
|
+
--github-owner your-org \
|
|
133
|
+
--github-repo your-repo
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Then start the database and sync:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
cd ~/projects/my-team
|
|
140
|
+
docker compose up -d
|
|
141
|
+
argustack sync
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
All available flags:
|
|
145
|
+
|
|
146
|
+
| Flag | Description |
|
|
147
|
+
|------|-------------|
|
|
148
|
+
| `--no-interactive` | Run without prompts — all values from flags |
|
|
149
|
+
| `-d, --dir <path>` | Workspace directory (default: current) |
|
|
150
|
+
| `-s, --source <list>` | Comma-separated: `jira,git,github,csv,db` |
|
|
151
|
+
| `--jira-url <url>` | Jira instance URL |
|
|
152
|
+
| `--jira-email <email>` | Jira user email |
|
|
153
|
+
| `--jira-token <token>` | Jira API token |
|
|
154
|
+
| `--jira-projects <keys>` | Comma-separated project keys, or `all` |
|
|
155
|
+
| `--git-repo <paths>` | Git repo paths, comma-separated |
|
|
156
|
+
| `--github-token <token>` | GitHub Personal Access Token |
|
|
157
|
+
| `--github-owner <owner>` | GitHub repo owner |
|
|
158
|
+
| `--github-repo <repo>` | GitHub repo name |
|
|
159
|
+
| `--csv-file <path>` | Path to Jira CSV export file |
|
|
160
|
+
| `--db-port <port>` | Argustack PostgreSQL port (default: `5434`) |
|
|
161
|
+
| `--pgweb-port <port>` | pgweb UI port (default: `8086`) |
|
|
162
|
+
|
|
163
|
+
This mode is ideal for:
|
|
164
|
+
- **AI agents** — a project manager tells their AI agent "set up argustack" and it runs everything autonomously
|
|
165
|
+
- **CI/CD pipelines** — automated workspace provisioning
|
|
166
|
+
- **Scripted setups** — reproducible environment creation
|
|
167
|
+
|
|
168
|
+
Browse your data at [localhost:8086](http://localhost:8086) — pgweb UI for running SQL queries and exploring tables in your browser.
|
|
169
|
+
|
|
170
|
+
### Connect to Claude
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
argustack mcp install
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Adds Argustack as an MCP server to Claude Desktop. Now you can ask Claude questions about your project data directly.
|
|
177
|
+
|
|
178
|
+
## Commands
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
argustack init # create workspace (interactive prompts)
|
|
182
|
+
argustack init --no-interactive ... # create workspace from CLI flags (no prompts)
|
|
183
|
+
argustack sync # pull data from all configured sources
|
|
184
|
+
argustack sync jira # pull Jira only
|
|
185
|
+
argustack sync git # pull Git commits only
|
|
186
|
+
argustack sync github # pull GitHub PRs, reviews, releases
|
|
187
|
+
argustack sync csv # import from Jira CSV export
|
|
188
|
+
argustack sync csv -f /path/to.csv # import specific CSV file
|
|
189
|
+
argustack sync -p PROJ # pull specific Jira project
|
|
190
|
+
argustack sync --since 2025-01-01 # incremental pull (only new/updated)
|
|
191
|
+
argustack sources # list configured sources
|
|
192
|
+
argustack status # workspace info
|
|
193
|
+
argustack embed # generate embeddings for semantic search
|
|
194
|
+
argustack mcp install # connect to Claude Desktop
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## What gets stored
|
|
198
|
+
|
|
199
|
+
All data goes into local PostgreSQL in Docker on your machine (nothing leaves `localhost`):
|
|
200
|
+
|
|
201
|
+
### Jira tables
|
|
202
|
+
|
|
203
|
+
| Table | Content |
|
|
204
|
+
|-------|---------|
|
|
205
|
+
| `issues` | All issues — typed columns + `custom_fields` JSONB + full `raw_json` |
|
|
206
|
+
| `issue_comments` | Comments with authors and timestamps |
|
|
207
|
+
| `issue_changelogs` | Every field change in history |
|
|
208
|
+
| `issue_worklogs` | Time tracking entries |
|
|
209
|
+
| `issue_links` | Issue-to-issue relationships |
|
|
210
|
+
|
|
211
|
+
Every custom field is preserved exactly as Jira returns it. 500 custom fields? All stored. Zero filtering, zero data loss.
|
|
212
|
+
|
|
213
|
+
### Git tables
|
|
214
|
+
|
|
215
|
+
| Table | Content |
|
|
216
|
+
|-------|---------|
|
|
217
|
+
| `commits` | Commit hash, message, author, email, date, full-text search |
|
|
218
|
+
| `commit_files` | Per-file changes — path, status, additions, deletions |
|
|
219
|
+
| `commit_issue_refs` | Cross-reference: commit ↔ Jira issue (extracted from commit messages) |
|
|
220
|
+
|
|
221
|
+
Commit messages mentioning issue keys like `PAP-123` or `PROJ-45` are automatically linked to Jira issues.
|
|
222
|
+
|
|
223
|
+
### GitHub tables
|
|
224
|
+
|
|
225
|
+
Select "GitHub" during `argustack init` or add later with `argustack source add github`:
|
|
226
|
+
|
|
227
|
+
| Table | Content |
|
|
228
|
+
|-------|---------|
|
|
229
|
+
| `pull_requests` | PRs — state, author, reviewers, additions/deletions, merge info, full-text search |
|
|
230
|
+
| `pr_reviews` | Review approvals and change requests |
|
|
231
|
+
| `pr_comments` | Inline review comments with file paths and line numbers |
|
|
232
|
+
| `pr_files` | Per-file changes in each PR |
|
|
233
|
+
| `pr_issue_refs` | Cross-reference: PR ↔ Jira issue (extracted from PR title and body) |
|
|
234
|
+
| `releases` | GitHub releases with tags, notes, and full-text search |
|
|
235
|
+
|
|
236
|
+
PR titles and bodies mentioning issue keys like `PAP-123` are automatically linked to Jira issues — just like commits.
|
|
237
|
+
|
|
238
|
+
## MCP Tools
|
|
239
|
+
|
|
240
|
+
When connected to Claude, these tools are available:
|
|
241
|
+
|
|
242
|
+
### Jira tools
|
|
243
|
+
|
|
244
|
+
| Tool | What it does |
|
|
245
|
+
|------|-------------|
|
|
246
|
+
| `query_issues` | Search issues — full-text, filters, or raw SQL |
|
|
247
|
+
| `get_issue` | Full issue details with comments, changelogs, custom fields |
|
|
248
|
+
| `issue_stats` | Aggregate stats — by status, type, assignee, project |
|
|
249
|
+
| `pull_jira` | Sync latest data from Jira |
|
|
250
|
+
| `list_projects` | List available Jira projects |
|
|
251
|
+
|
|
252
|
+
### Git tools
|
|
253
|
+
|
|
254
|
+
| Tool | What it does |
|
|
255
|
+
|------|-------------|
|
|
256
|
+
| `query_commits` | Search commits by text, author, date, file path, or raw SQL. Optional `repo_path` filter for multi-repo workspaces |
|
|
257
|
+
| `issue_commits` | Cross-reference: find all commits mentioning a Jira issue key. Optional `repo_path` filter |
|
|
258
|
+
| `commit_stats` | Aggregate stats — top authors, most changed files, linked issues. Optional `repo_path` filter |
|
|
259
|
+
|
|
260
|
+
### GitHub tools
|
|
261
|
+
|
|
262
|
+
| Tool | What it does |
|
|
263
|
+
|------|-------------|
|
|
264
|
+
| `query_prs` | Search PRs — full-text, state, author, base branch, or raw SQL |
|
|
265
|
+
| `issue_prs` | Cross-reference: find all PRs mentioning a Jira issue key with reviews |
|
|
266
|
+
| `query_releases` | List releases with full-text search |
|
|
267
|
+
|
|
268
|
+
### Cross-source tools
|
|
269
|
+
|
|
270
|
+
| Tool | What it does |
|
|
271
|
+
|------|-------------|
|
|
272
|
+
| `issue_timeline` | Chronological timeline — changelogs + commits + PRs for one issue |
|
|
273
|
+
| `semantic_search` | Find similar issues by meaning (pgvector embeddings) |
|
|
274
|
+
| `estimate` | Predict effort for new tasks — finds similar completed tasks, analyzes developer profiles, cycle/coding time, bug rate |
|
|
275
|
+
|
|
276
|
+
### System tools
|
|
277
|
+
|
|
278
|
+
| Tool | What it does |
|
|
279
|
+
|------|-------------|
|
|
280
|
+
| `workspace_info` | Current workspace configuration |
|
|
281
|
+
|
|
282
|
+
## Embeddings & Semantic Search
|
|
283
|
+
|
|
284
|
+
**Embeddings** turn issue text into numerical vectors that capture meaning. Two issues about "login not working" and "SSO authentication fails" will have similar vectors — even though they share zero keywords.
|
|
285
|
+
|
|
286
|
+
How it works:
|
|
287
|
+
|
|
288
|
+
1. `argustack embed` sends each issue's `summary + description` to OpenAI API (`text-embedding-3-small` model)
|
|
289
|
+
2. Returns a 1536-dimensional vector per issue, stored in PostgreSQL via pgvector
|
|
290
|
+
3. `semantic_search` MCP tool embeds your question, then finds issues with the closest vectors using cosine similarity
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
# Generate embeddings for all issues (requires OPENAI_API_KEY in .env)
|
|
294
|
+
argustack embed
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
After embedding, ask Claude: *"Find issues similar to payment timeout errors"* — it will search by meaning, not keywords.
|
|
298
|
+
|
|
299
|
+
**Costs:** text-embedding-3-small costs ~$0.02 per 1M tokens. 10,000 issues ≈ $0.05-0.10.
|
|
300
|
+
|
|
301
|
+
**Optional:** Embeddings require an OpenAI API key. All other features work without it.
|
|
302
|
+
|
|
303
|
+
## GitHub token setup
|
|
304
|
+
|
|
305
|
+
Argustack only reads data from GitHub — it never writes anything. You need a **fine-grained Personal Access Token** with read-only permissions.
|
|
306
|
+
|
|
307
|
+
1. Go to [github.com/settings/personal-access-tokens/new](https://github.com/settings/personal-access-tokens/new)
|
|
308
|
+
2. **Token name** — anything (e.g. `argustack`)
|
|
309
|
+
3. **Description** — optional, can leave empty
|
|
310
|
+
4. **Resource owner** — your account, or the organization that owns the repo
|
|
311
|
+
5. **Expiration** — "No expiration" recommended. Token is read-only and stays in your local `.env`
|
|
312
|
+
6. **Repository access** — pick one:
|
|
313
|
+
- **Only select repositories** (recommended) — pick specific repos, max 50
|
|
314
|
+
- **All repositories** — all your current and future repos
|
|
315
|
+
- **Public repositories** — read-only access to public repos only
|
|
316
|
+
5. **Permissions** → Repository permissions (3 total):
|
|
317
|
+
|
|
318
|
+
| Permission | Access | Why |
|
|
319
|
+
|---|---|---|
|
|
320
|
+
| **Contents** | Read-only | Releases, downloads, tags |
|
|
321
|
+
| **Metadata** | Read-only | Repository info (auto-selected, required) |
|
|
322
|
+
| **Pull requests** | Read-only | PRs, reviews, comments, files |
|
|
323
|
+
|
|
324
|
+
7. Click "Generate token" and copy it
|
|
325
|
+
|
|
326
|
+
During `argustack init`, select "GitHub" as a source and paste the token when asked. Or add to `.env` manually:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
GITHUB_TOKEN=github_pat_...
|
|
330
|
+
GITHUB_OWNER=your-org
|
|
331
|
+
GITHUB_REPO=your-repo
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Then run `argustack source add github` and `argustack sync github`.
|
|
335
|
+
|
|
336
|
+
## Multiple workspaces
|
|
337
|
+
|
|
338
|
+
Each data source = separate workspace (like git repos):
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
~/projects/
|
|
342
|
+
├── client-alpha/ # argustack init → Alpha's Jira + Git
|
|
343
|
+
│ ├── .argustack/
|
|
344
|
+
│ ├── .env # Alpha credentials
|
|
345
|
+
│ └── docker-compose.yml
|
|
346
|
+
│
|
|
347
|
+
├── client-beta/ # argustack init → Beta's Jira + Git
|
|
348
|
+
│ ├── .argustack/
|
|
349
|
+
│ ├── .env # Beta credentials
|
|
350
|
+
│ └── docker-compose.yml
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## Security & Credentials
|
|
354
|
+
|
|
355
|
+
**Argustack is a CLI tool. It has no backend, no cloud, no accounts.** Everything runs on your machine.
|
|
356
|
+
|
|
357
|
+
When you run `argustack init`, it creates a `.env` file in your workspace with your credentials:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
# .env — YOUR file, on YOUR machine, never uploaded anywhere
|
|
361
|
+
|
|
362
|
+
# === Jira ===
|
|
363
|
+
JIRA_URL=https://your-team.atlassian.net
|
|
364
|
+
JIRA_EMAIL=you@company.com
|
|
365
|
+
JIRA_API_TOKEN=your-api-token-here
|
|
366
|
+
JIRA_PROJECTS=PROJ,OTHER
|
|
367
|
+
|
|
368
|
+
# === Git ===
|
|
369
|
+
GIT_REPO_PATHS=/path/to/repo1,/path/to/repo2
|
|
370
|
+
|
|
371
|
+
# === GitHub ===
|
|
372
|
+
GITHUB_TOKEN=github_pat_...
|
|
373
|
+
GITHUB_OWNER=your-org
|
|
374
|
+
GITHUB_REPO=your-repo
|
|
375
|
+
|
|
376
|
+
# === Argustack internal PostgreSQL (match docker-compose.yml) ===
|
|
377
|
+
DB_HOST=localhost
|
|
378
|
+
DB_PORT=5434
|
|
379
|
+
DB_USER=argustack
|
|
380
|
+
DB_PASSWORD=argustack_local
|
|
381
|
+
DB_NAME=argustack
|
|
382
|
+
|
|
383
|
+
# === OpenAI embeddings (optional, for semantic search) ===
|
|
384
|
+
# OPENAI_API_KEY=sk-...
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
**Where credentials go:**
|
|
388
|
+
|
|
389
|
+
| What | Where | Who can see |
|
|
390
|
+
|------|-------|-------------|
|
|
391
|
+
| Jira token | `.env` on your disk | Only you |
|
|
392
|
+
| GitHub token | `.env` on your disk | Only you |
|
|
393
|
+
| Jira data | PostgreSQL in Docker on `localhost:5434` | Only you |
|
|
394
|
+
| Git + GitHub data | PostgreSQL in Docker on `localhost:5434` | Only you |
|
|
395
|
+
| Database password | `.env` on your disk | Only you |
|
|
396
|
+
| Source code (this repo) | GitHub | Everyone — **no secrets here** |
|
|
397
|
+
|
|
398
|
+
**What Argustack does NOT do:**
|
|
399
|
+
- Does not send your data to any external server
|
|
400
|
+
- Does not have analytics, telemetry, or tracking
|
|
401
|
+
- Does not store credentials anywhere except your local `.env`
|
|
402
|
+
- Does not require registration or accounts
|
|
403
|
+
|
|
404
|
+
**`.env` is in `.gitignore`** — if you accidentally run `git add .`, your credentials won't be committed.
|
|
405
|
+
|
|
406
|
+
## Tech Stack
|
|
407
|
+
|
|
408
|
+
- TypeScript / Node.js
|
|
409
|
+
- Commander.js — CLI
|
|
410
|
+
- jira.js — Jira REST API
|
|
411
|
+
- Octokit — GitHub REST API (PRs, reviews, releases)
|
|
412
|
+
- es-git — native Git bindings (N-API, powered by libgit2)
|
|
413
|
+
- PostgreSQL 16 + pgvector — storage + vector search
|
|
414
|
+
- MCP SDK — Claude integration
|
|
415
|
+
- Docker — database infrastructure
|
|
416
|
+
|
|
417
|
+
## Roadmap
|
|
418
|
+
|
|
419
|
+
- [x] Jira pull (all fields, comments, changelogs, worklogs, links)
|
|
420
|
+
- [x] Git pull (commits, per-file diffs, issue cross-references)
|
|
421
|
+
- [x] GitHub pull (PRs, reviews, comments, files, releases, Jira cross-references)
|
|
422
|
+
- [x] MCP server for Claude Desktop / Claude Code (15 tools)
|
|
423
|
+
- [x] Embeddings + semantic search (OpenAI text-embedding-3-small, pgvector)
|
|
424
|
+
- [x] Cross-source timeline (issue_timeline: changelogs + commits + PRs)
|
|
425
|
+
- [x] Multi-repo Git support (multiple repos per workspace, `GIT_REPO_PATHS`)
|
|
426
|
+
- [x] Progress indicators during sync (e.g. `150/506 issues (30%)`)
|
|
427
|
+
- [ ] Database adapter (schema, sample data)
|
|
428
|
+
- [ ] Cross-source analysis (Jira ticket vs actual code vs DB state)
|
|
429
|
+
- [x] CSV import (Jira export without API token)
|
|
430
|
+
|
|
431
|
+
## License
|
|
432
|
+
|
|
433
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/csv/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/csv/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAqB,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAkB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Issue, IssueComment, IssueWorklog, IssueLink } from '../../core/types/index.js';
|
|
2
|
+
import type { CsvSchema } from './parser.js';
|
|
3
|
+
export interface CsvRowResult {
|
|
4
|
+
issue: Issue;
|
|
5
|
+
comments: IssueComment[];
|
|
6
|
+
worklogs: IssueWorklog[];
|
|
7
|
+
links: IssueLink[];
|
|
8
|
+
}
|
|
9
|
+
export declare function mapCsvRow(row: string[], schema: CsvSchema): CsvRowResult;
|
|
10
|
+
//# sourceMappingURL=mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../../../src/adapters/csv/mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,YAAY,EACZ,YAAY,EACZ,SAAS,EACV,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAcD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,SAAS,GAAG,YAAY,CAsCxE"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { parseJiraDate } from './parser.js';
|
|
2
|
+
function cell(row, index) {
|
|
3
|
+
if (index === undefined) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
const value = row[index]?.trim() ?? '';
|
|
7
|
+
return value === '' ? null : value;
|
|
8
|
+
}
|
|
9
|
+
function cellStr(row, index) {
|
|
10
|
+
return cell(row, index) ?? '';
|
|
11
|
+
}
|
|
12
|
+
export function mapCsvRow(row, schema) {
|
|
13
|
+
const sf = schema.standardFields;
|
|
14
|
+
const issueKey = cellStr(row, sf.get('Issue key'));
|
|
15
|
+
const projectKey = issueKey.split('-')[0] ?? '';
|
|
16
|
+
const issue = {
|
|
17
|
+
key: issueKey,
|
|
18
|
+
id: cellStr(row, sf.get('Issue id')),
|
|
19
|
+
projectKey,
|
|
20
|
+
summary: cellStr(row, sf.get('Summary')),
|
|
21
|
+
description: cell(row, sf.get('Description')),
|
|
22
|
+
issueType: cell(row, sf.get('Issue Type')),
|
|
23
|
+
status: cell(row, sf.get('Status')),
|
|
24
|
+
statusCategory: cell(row, sf.get('Status Category')),
|
|
25
|
+
priority: cell(row, sf.get('Priority')),
|
|
26
|
+
resolution: cell(row, sf.get('Resolution')),
|
|
27
|
+
assignee: cell(row, sf.get('Assignee')),
|
|
28
|
+
reporter: cell(row, sf.get('Reporter')),
|
|
29
|
+
created: parseJiraDate(cell(row, sf.get('Created'))),
|
|
30
|
+
updated: parseJiraDate(cell(row, sf.get('Updated'))),
|
|
31
|
+
resolved: parseJiraDate(cell(row, sf.get('Resolved'))),
|
|
32
|
+
dueDate: cell(row, sf.get('Due date')),
|
|
33
|
+
labels: extractRepeated(row, schema, 'Labels'),
|
|
34
|
+
components: extractRepeated(row, schema, 'Components'),
|
|
35
|
+
fixVersions: extractRepeated(row, schema, 'Fix versions'),
|
|
36
|
+
parentKey: cell(row, sf.get('Parent key')),
|
|
37
|
+
sprint: null,
|
|
38
|
+
storyPoints: parseFloat(cell(row, sf.get('Original estimate')) ?? '') || null,
|
|
39
|
+
customFields: extractCustomFields(row, schema),
|
|
40
|
+
rawJson: buildRawJson(row, schema),
|
|
41
|
+
};
|
|
42
|
+
const comments = extractComments(issueKey, row, schema);
|
|
43
|
+
const worklogs = extractWorklogs(issueKey, row, schema);
|
|
44
|
+
const links = extractLinks(issueKey, row, schema);
|
|
45
|
+
return { issue, comments, worklogs, links };
|
|
46
|
+
}
|
|
47
|
+
function extractRepeated(row, schema, name) {
|
|
48
|
+
const group = schema.repeatedGroups.get(name);
|
|
49
|
+
if (!group) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const result = [];
|
|
53
|
+
for (let i = group.startIndex; i < group.startIndex + group.count; i++) {
|
|
54
|
+
const value = row[i]?.trim();
|
|
55
|
+
if (value) {
|
|
56
|
+
result.push(value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
function extractCustomFields(row, schema) {
|
|
62
|
+
const result = {};
|
|
63
|
+
for (const cf of schema.customFields) {
|
|
64
|
+
const value = cell(row, cf.columnIndex);
|
|
65
|
+
if (value !== null) {
|
|
66
|
+
result[cf.name] = value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
function buildRawJson(row, schema) {
|
|
72
|
+
const raw = {};
|
|
73
|
+
for (const [name, index] of schema.standardFields) {
|
|
74
|
+
raw[name] = cell(row, index);
|
|
75
|
+
}
|
|
76
|
+
for (const cf of schema.customFields) {
|
|
77
|
+
raw[`Custom field (${cf.name})`] = cell(row, cf.columnIndex);
|
|
78
|
+
}
|
|
79
|
+
return raw;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Jira CSV comment format: `timestamp;user_id;comment_text`
|
|
83
|
+
* Split on first 2 semicolons — comment body may contain semicolons.
|
|
84
|
+
*/
|
|
85
|
+
function extractComments(issueKey, row, schema) {
|
|
86
|
+
const group = schema.repeatedGroups.get('Comment');
|
|
87
|
+
if (!group) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const result = [];
|
|
91
|
+
for (let i = group.startIndex; i < group.startIndex + group.count; i++) {
|
|
92
|
+
const raw = row[i]?.trim();
|
|
93
|
+
if (!raw) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const firstSemi = raw.indexOf(';');
|
|
97
|
+
if (firstSemi === -1) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const secondSemi = raw.indexOf(';', firstSemi + 1);
|
|
101
|
+
if (secondSemi === -1) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const timestamp = raw.slice(0, firstSemi);
|
|
105
|
+
const author = raw.slice(firstSemi + 1, secondSemi);
|
|
106
|
+
const body = raw.slice(secondSemi + 1);
|
|
107
|
+
result.push({
|
|
108
|
+
issueKey,
|
|
109
|
+
commentId: `csv-${issueKey}-comment-${i}`,
|
|
110
|
+
author: author || null,
|
|
111
|
+
body: body || null,
|
|
112
|
+
created: parseJiraDate(timestamp),
|
|
113
|
+
updated: null,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Jira CSV worklog format: `description;timestamp;user;minutes`
|
|
120
|
+
* Minutes × 60 = seconds.
|
|
121
|
+
*/
|
|
122
|
+
function extractWorklogs(issueKey, row, schema) {
|
|
123
|
+
const group = schema.repeatedGroups.get('Log Work');
|
|
124
|
+
if (!group) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
const result = [];
|
|
128
|
+
for (let i = group.startIndex; i < group.startIndex + group.count; i++) {
|
|
129
|
+
const raw = row[i]?.trim();
|
|
130
|
+
if (!raw) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const parts = raw.split(';');
|
|
134
|
+
if (parts.length < 4) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const description = parts[0] ?? '';
|
|
138
|
+
const timestamp = parts[1] ?? '';
|
|
139
|
+
const author = parts[2] ?? '';
|
|
140
|
+
const minutesStr = parts[parts.length - 1] ?? '0';
|
|
141
|
+
const minutes = parseInt(minutesStr, 10);
|
|
142
|
+
result.push({
|
|
143
|
+
issueKey,
|
|
144
|
+
author: author || null,
|
|
145
|
+
timeSpent: isNaN(minutes) ? null : `${minutes}m`,
|
|
146
|
+
timeSpentSeconds: isNaN(minutes) ? null : minutes * 60,
|
|
147
|
+
comment: description || null,
|
|
148
|
+
started: parseJiraDate(timestamp),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
function extractLinks(issueKey, row, schema) {
|
|
154
|
+
const result = [];
|
|
155
|
+
for (const link of schema.issueLinks) {
|
|
156
|
+
const targetKey = row[link.columnIndex]?.trim();
|
|
157
|
+
if (!targetKey) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
if (link.direction === 'outward') {
|
|
161
|
+
result.push({
|
|
162
|
+
sourceKey: issueKey,
|
|
163
|
+
targetKey,
|
|
164
|
+
linkType: link.linkType,
|
|
165
|
+
direction: 'outward',
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
result.push({
|
|
170
|
+
sourceKey: targetKey,
|
|
171
|
+
targetKey: issueKey,
|
|
172
|
+
linkType: link.linkType,
|
|
173
|
+
direction: 'inward',
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.js","sourceRoot":"","sources":["../../../src/adapters/csv/mapper.ts"],"names":[],"mappings":"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"}
|