issy 0.1.8 → 0.1.9

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 (3) hide show
  1. package/README.md +6 -0
  2. package/bin/issy +101 -97
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -25,6 +25,8 @@ Opens a local UI at `http://localhost:1554`.
25
25
  ### CLI
26
26
 
27
27
  ```bash
28
+ issy init # Create .issues/ directory
29
+ issy init --seed # Create with a welcome issue
28
30
  issy list # List open issues
29
31
  issy search "auth" # Fuzzy search
30
32
  issy read 0001 # View issue
@@ -34,6 +36,10 @@ issy close 0001 # Close issue
34
36
 
35
37
  Run `issy help` for full options.
36
38
 
39
+ ### Monorepo Support
40
+
41
+ issy walks up from the current directory to find an existing `.issues/` folder, so you can run it from any subdirectory.
42
+
37
43
  ## Configuration
38
44
 
39
45
  | Variable | Description | Default |
package/bin/issy CHANGED
@@ -1,38 +1,38 @@
1
1
  #!/usr/bin/env node
2
- import { dirname } from "node:path";
3
- import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
4
- import { join, resolve } from "node:path";
5
- import { fileURLToPath } from "node:url";
2
+ import { dirname } from 'node:path'
3
+ import { existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs'
4
+ import { join, resolve } from 'node:path'
5
+ import { fileURLToPath } from 'node:url'
6
6
 
7
- const args = process.argv.slice(2);
7
+ const args = process.argv.slice(2)
8
8
  const cliCommands = new Set([
9
- "list",
10
- "search",
11
- "read",
12
- "create",
13
- "update",
14
- "close",
15
- "help",
16
- "--help",
17
- "-h",
18
- ]);
9
+ 'list',
10
+ 'search',
11
+ 'read',
12
+ 'create',
13
+ 'update',
14
+ 'close',
15
+ 'help',
16
+ '--help',
17
+ '-h'
18
+ ])
19
19
 
20
20
  /**
21
21
  * Find .issues directory by walking up from the given path.
22
22
  * Returns the path if found, or null if not found.
23
23
  */
24
24
  function findIssuesDirUpward(fromPath) {
25
- let current = resolve(fromPath);
26
- for (let i = 0; i < 20; i++) {
27
- const candidate = join(current, ".issues");
28
- if (existsSync(candidate)) {
29
- return candidate;
30
- }
31
- const parent = dirname(current);
32
- if (parent === current) break;
33
- current = parent;
34
- }
35
- return null;
25
+ let current = resolve(fromPath)
26
+ for (let i = 0; i < 20; i++) {
27
+ const candidate = join(current, '.issues')
28
+ if (existsSync(candidate)) {
29
+ return candidate
30
+ }
31
+ const parent = dirname(current)
32
+ if (parent === current) break
33
+ current = parent
34
+ }
35
+ return null
36
36
  }
37
37
 
38
38
  /**
@@ -40,17 +40,17 @@ function findIssuesDirUpward(fromPath) {
40
40
  * Returns the directory containing .git, or null if not in a git repo.
41
41
  */
42
42
  function findGitRoot(fromPath) {
43
- let current = resolve(fromPath);
44
- for (let i = 0; i < 20; i++) {
45
- const gitDir = join(current, ".git");
46
- if (existsSync(gitDir)) {
47
- return current;
48
- }
49
- const parent = dirname(current);
50
- if (parent === current) break;
51
- current = parent;
52
- }
53
- return null;
43
+ let current = resolve(fromPath)
44
+ for (let i = 0; i < 20; i++) {
45
+ const gitDir = join(current, '.git')
46
+ if (existsSync(gitDir)) {
47
+ return current
48
+ }
49
+ const parent = dirname(current)
50
+ if (parent === current) break
51
+ current = parent
52
+ }
53
+ return null
54
54
  }
55
55
 
56
56
  /**
@@ -61,78 +61,82 @@ function findGitRoot(fromPath) {
61
61
  * 4. Fall back to creating .issues in ISSUES_ROOT or cwd
62
62
  */
63
63
  function resolveIssuesDir() {
64
- // 1. Explicit override
65
- if (process.env.ISSUES_DIR) {
66
- return resolve(process.env.ISSUES_DIR);
67
- }
68
-
69
- // 2. Try to find existing .issues by walking up
70
- const startDir = process.env.ISSUES_ROOT || process.cwd();
71
- const found = findIssuesDirUpward(startDir);
72
- if (found) {
73
- return found;
74
- }
75
-
76
- // 3. If in a git repo, use .issues at the repo root
77
- const gitRoot = findGitRoot(startDir);
78
- if (gitRoot) {
79
- return join(gitRoot, ".issues");
80
- }
81
-
82
- // 4. Fall back to creating in start directory
83
- return join(resolve(startDir), ".issues");
64
+ // 1. Explicit override
65
+ if (process.env.ISSUES_DIR) {
66
+ return resolve(process.env.ISSUES_DIR)
67
+ }
68
+
69
+ // 2. Try to find existing .issues by walking up
70
+ const startDir = process.env.ISSUES_ROOT || process.cwd()
71
+ const found = findIssuesDirUpward(startDir)
72
+ if (found) {
73
+ return found
74
+ }
75
+
76
+ // 3. If in a git repo, use .issues at the repo root
77
+ const gitRoot = findGitRoot(startDir)
78
+ if (gitRoot) {
79
+ return join(gitRoot, '.issues')
80
+ }
81
+
82
+ // 4. Fall back to creating in start directory
83
+ return join(resolve(startDir), '.issues')
84
84
  }
85
85
 
86
- const issuesDir = resolveIssuesDir();
86
+ const issuesDir = resolveIssuesDir()
87
87
  // Set env vars for downstream consumers
88
- process.env.ISSUES_DIR = issuesDir;
88
+ process.env.ISSUES_DIR = issuesDir
89
89
  // Set ISSUES_ROOT to the parent of .issues for consistency
90
- process.env.ISSUES_ROOT = dirname(issuesDir);
90
+ process.env.ISSUES_ROOT = dirname(issuesDir)
91
91
 
92
- if (cliCommands.has(args[0] || "")) {
93
- const here = resolve(fileURLToPath(import.meta.url), "..");
94
- const entry = resolve(here, "..", "dist", "cli.js");
95
- process.argv = [process.argv[0], process.argv[1], ...args];
96
- const cli = await import(entry);
97
- await cli.ready; // Wait for main() to complete before exiting
98
- process.exit(0);
92
+ if (cliCommands.has(args[0] || '')) {
93
+ const here = resolve(fileURLToPath(import.meta.url), '..')
94
+ const entry = resolve(here, '..', 'dist', 'cli.js')
95
+ process.argv = [process.argv[0], process.argv[1], ...args]
96
+ const cli = await import(entry)
97
+ await cli.ready // Wait for main() to complete before exiting
98
+ process.exit(0)
99
99
  }
100
100
 
101
- const portIdx = args.findIndex((arg) => arg === "--port" || arg === "-p");
101
+ const portIdx = args.findIndex(arg => arg === '--port' || arg === '-p')
102
102
  if (portIdx >= 0 && args[portIdx + 1]) {
103
- process.env.ISSUES_PORT = args[portIdx + 1];
103
+ process.env.ISSUES_PORT = args[portIdx + 1]
104
104
  }
105
105
 
106
- const shouldInitOnly = args.includes("init");
107
- const skipSeed = args.includes("--no-seed");
108
-
109
- if (!existsSync(issuesDir)) {
110
- mkdirSync(issuesDir, { recursive: true });
111
- }
112
-
113
- if (!skipSeed) {
114
- const hasIssues =
115
- existsSync(issuesDir) && readdirSync(issuesDir).some((f) => f.endsWith(".md"));
116
- if (!hasIssues) {
117
- const welcome = `---\n` +
118
- `title: Welcome to issy\n` +
119
- `description: Your first issue in this repo\n` +
120
- `priority: medium\n` +
121
- `type: improvement\n` +
122
- `status: open\n` +
123
- `created: ${new Date().toISOString().slice(0, 19)}\n` +
124
- `---\n\n` +
125
- `## Details\n\n` +
126
- `- This issue was created automatically on first run.\n` +
127
- `- Edit it, close it, or delete it to get started.\n`;
128
- writeFileSync(join(issuesDir, "0001-welcome-to-issy.md"), welcome);
129
- }
130
- }
106
+ const shouldInitOnly = args.includes('init')
107
+ const shouldSeed = args.includes('--seed')
131
108
 
109
+ // Only create .issues directory on explicit 'init' command
132
110
  if (shouldInitOnly) {
133
- console.log(`Initialized ${issuesDir}`);
134
- process.exit(0);
111
+ if (!existsSync(issuesDir)) {
112
+ mkdirSync(issuesDir, { recursive: true })
113
+ }
114
+
115
+ // Only seed with welcome issue if --seed flag is passed
116
+ if (shouldSeed) {
117
+ const hasIssues =
118
+ existsSync(issuesDir) &&
119
+ readdirSync(issuesDir).some(f => f.endsWith('.md'))
120
+ if (!hasIssues) {
121
+ const welcome =
122
+ `---\n` +
123
+ `title: Welcome to issy\n` +
124
+ `description: Your first issue in this repo\n` +
125
+ `priority: medium\n` +
126
+ `type: improvement\n` +
127
+ `status: open\n` +
128
+ `created: ${new Date().toISOString().slice(0, 19)}\n` +
129
+ `---\n\n` +
130
+ `## Details\n\n` +
131
+ `- This issue was created automatically on first run.\n` +
132
+ `- Edit it, close it, or delete it to get started.\n`
133
+ writeFileSync(join(issuesDir, '0001-welcome-to-issy.md'), welcome)
134
+ }
135
+ }
136
+
137
+ console.log(`Initialized ${issuesDir}`)
138
+ process.exit(0)
135
139
  }
136
140
 
137
141
  // Start the server
138
- await import("@miketromba/issy-app");
142
+ await import('@miketromba/issy-app')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "issy",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "AI-native issue tracking. Markdown files in .issues/, managed by your coding assistant.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -34,7 +34,7 @@
34
34
  "lint": "biome check src bin"
35
35
  },
36
36
  "dependencies": {
37
- "@miketromba/issy-app": "^0.1.8",
38
- "@miketromba/issy-core": "^0.1.8"
37
+ "@miketromba/issy-app": "^0.1.9",
38
+ "@miketromba/issy-core": "^0.1.9"
39
39
  }
40
40
  }