@2amtech/hai 0.0.1
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/README.md +212 -0
- package/dist/ai/agent-info.d.ts +1 -0
- package/dist/ai/agent-info.js +42 -0
- package/dist/ai/agent-info.js.map +1 -0
- package/dist/ai/agents/architect.d.ts +3 -0
- package/dist/ai/agents/architect.js +107 -0
- package/dist/ai/agents/architect.js.map +1 -0
- package/dist/ai/agents/backend-dev.d.ts +3 -0
- package/dist/ai/agents/backend-dev.js +33 -0
- package/dist/ai/agents/backend-dev.js.map +1 -0
- package/dist/ai/agents/frontend-dev.d.ts +3 -0
- package/dist/ai/agents/frontend-dev.js +31 -0
- package/dist/ai/agents/frontend-dev.js.map +1 -0
- package/dist/ai/agents/index.d.ts +3 -0
- package/dist/ai/agents/index.js +17 -0
- package/dist/ai/agents/index.js.map +1 -0
- package/dist/ai/agents/refactorer.d.ts +3 -0
- package/dist/ai/agents/refactorer.js +38 -0
- package/dist/ai/agents/refactorer.js.map +1 -0
- package/dist/ai/agents/researcher.d.ts +3 -0
- package/dist/ai/agents/researcher.js +28 -0
- package/dist/ai/agents/researcher.js.map +1 -0
- package/dist/ai/agents/security-reviewer.d.ts +3 -0
- package/dist/ai/agents/security-reviewer.js +99 -0
- package/dist/ai/agents/security-reviewer.js.map +1 -0
- package/dist/ai/agents/types.d.ts +6 -0
- package/dist/ai/agents/types.js +2 -0
- package/dist/ai/agents/types.js.map +1 -0
- package/dist/ai/agents/verifier.d.ts +3 -0
- package/dist/ai/agents/verifier.js +28 -0
- package/dist/ai/agents/verifier.js.map +1 -0
- package/dist/ai/prompts/document.d.ts +3 -0
- package/dist/ai/prompts/document.js +57 -0
- package/dist/ai/prompts/document.js.map +1 -0
- package/dist/ai/prompts/implement.d.ts +3 -0
- package/dist/ai/prompts/implement.js +128 -0
- package/dist/ai/prompts/implement.js.map +1 -0
- package/dist/ai/prompts/index.d.ts +3 -0
- package/dist/ai/prompts/index.js +17 -0
- package/dist/ai/prompts/index.js.map +1 -0
- package/dist/ai/prompts/optimize-ai.d.ts +3 -0
- package/dist/ai/prompts/optimize-ai.js +104 -0
- package/dist/ai/prompts/optimize-ai.js.map +1 -0
- package/dist/ai/prompts/pull-specs.d.ts +3 -0
- package/dist/ai/prompts/pull-specs.js +10 -0
- package/dist/ai/prompts/pull-specs.js.map +1 -0
- package/dist/ai/prompts/pull-tickets.d.ts +3 -0
- package/dist/ai/prompts/pull-tickets.js +11 -0
- package/dist/ai/prompts/pull-tickets.js.map +1 -0
- package/dist/ai/prompts/pull.d.ts +3 -0
- package/dist/ai/prompts/pull.js +9 -0
- package/dist/ai/prompts/pull.js.map +1 -0
- package/dist/ai/prompts/review-changes.d.ts +3 -0
- package/dist/ai/prompts/review-changes.js +88 -0
- package/dist/ai/prompts/review-changes.js.map +1 -0
- package/dist/ai/prompts/types.d.ts +6 -0
- package/dist/ai/prompts/types.js +2 -0
- package/dist/ai/prompts/types.js.map +1 -0
- package/dist/app.d.ts +14 -0
- package/dist/app.js +40 -0
- package/dist/app.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +79 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/get.d.ts +8 -0
- package/dist/commands/get.js +73 -0
- package/dist/commands/get.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.js +113 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp/helpers.d.ts +15 -0
- package/dist/commands/mcp/helpers.js +21 -0
- package/dist/commands/mcp/helpers.js.map +1 -0
- package/dist/commands/mcp/pull.d.ts +3 -0
- package/dist/commands/mcp/pull.js +85 -0
- package/dist/commands/mcp/pull.js.map +1 -0
- package/dist/commands/mcp/server.d.ts +2 -0
- package/dist/commands/mcp/server.js +80 -0
- package/dist/commands/mcp/server.js.map +1 -0
- package/dist/commands/mcp/specs.d.ts +2 -0
- package/dist/commands/mcp/specs.js +325 -0
- package/dist/commands/mcp/specs.js.map +1 -0
- package/dist/commands/mcp/tickets.d.ts +3 -0
- package/dist/commands/mcp/tickets.js +77 -0
- package/dist/commands/mcp/tickets.js.map +1 -0
- package/dist/commands/pull.d.ts +10 -0
- package/dist/commands/pull.js +61 -0
- package/dist/commands/pull.js.map +1 -0
- package/dist/commands/status.d.ts +2 -0
- package/dist/commands/status.js +102 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/components/ticket-renderer.d.ts +5 -0
- package/dist/components/ticket-renderer.js +89 -0
- package/dist/components/ticket-renderer.js.map +1 -0
- package/dist/contexts/config-context.d.ts +17 -0
- package/dist/contexts/config-context.js +77 -0
- package/dist/contexts/config-context.js.map +1 -0
- package/dist/contexts/error-context.d.ts +12 -0
- package/dist/contexts/error-context.js +28 -0
- package/dist/contexts/error-context.js.map +1 -0
- package/dist/helpers/config.d.ts +4 -0
- package/dist/helpers/config.js +29 -0
- package/dist/helpers/config.js.map +1 -0
- package/dist/helpers/fs.d.ts +8 -0
- package/dist/helpers/fs.js +83 -0
- package/dist/helpers/fs.js.map +1 -0
- package/dist/helpers/init.d.ts +2 -0
- package/dist/helpers/init.js +18 -0
- package/dist/helpers/init.js.map +1 -0
- package/dist/helpers/preflight.d.ts +8 -0
- package/dist/helpers/preflight.js +77 -0
- package/dist/helpers/preflight.js.map +1 -0
- package/dist/helpers/pull.d.ts +9 -0
- package/dist/helpers/pull.js +79 -0
- package/dist/helpers/pull.js.map +1 -0
- package/dist/helpers/symlink.d.ts +9 -0
- package/dist/helpers/symlink.js +104 -0
- package/dist/helpers/symlink.js.map +1 -0
- package/dist/helpers/tickets.d.ts +4 -0
- package/dist/helpers/tickets.js +56 -0
- package/dist/helpers/tickets.js.map +1 -0
- package/dist/hooks/use-async.d.ts +6 -0
- package/dist/hooks/use-async.js +37 -0
- package/dist/hooks/use-async.js.map +1 -0
- package/dist/plugins/atlassian/adf-to-markdown.d.ts +11 -0
- package/dist/plugins/atlassian/adf-to-markdown.js +121 -0
- package/dist/plugins/atlassian/adf-to-markdown.js.map +1 -0
- package/dist/plugins/atlassian/auth-step.d.ts +10 -0
- package/dist/plugins/atlassian/auth-step.js +59 -0
- package/dist/plugins/atlassian/auth-step.js.map +1 -0
- package/dist/plugins/atlassian/confluence-client.d.ts +24 -0
- package/dist/plugins/atlassian/confluence-client.js +250 -0
- package/dist/plugins/atlassian/confluence-client.js.map +1 -0
- package/dist/plugins/atlassian/data.d.ts +18 -0
- package/dist/plugins/atlassian/data.js +12 -0
- package/dist/plugins/atlassian/data.js.map +1 -0
- package/dist/plugins/atlassian/index.d.ts +2 -0
- package/dist/plugins/atlassian/index.js +57 -0
- package/dist/plugins/atlassian/index.js.map +1 -0
- package/dist/plugins/atlassian/init-step.d.ts +11 -0
- package/dist/plugins/atlassian/init-step.js +54 -0
- package/dist/plugins/atlassian/init-step.js.map +1 -0
- package/dist/plugins/atlassian/jira-client.d.ts +38 -0
- package/dist/plugins/atlassian/jira-client.js +308 -0
- package/dist/plugins/atlassian/jira-client.js.map +1 -0
- package/dist/plugins/atlassian/specs-step.d.ts +13 -0
- package/dist/plugins/atlassian/specs-step.js +71 -0
- package/dist/plugins/atlassian/specs-step.js.map +1 -0
- package/dist/plugins/atlassian/tickets-step.d.ts +8 -0
- package/dist/plugins/atlassian/tickets-step.js +45 -0
- package/dist/plugins/atlassian/tickets-step.js.map +1 -0
- package/dist/plugins/claude-code/agents.d.ts +4 -0
- package/dist/plugins/claude-code/agents.js +56 -0
- package/dist/plugins/claude-code/agents.js.map +1 -0
- package/dist/plugins/claude-code/commands.d.ts +4 -0
- package/dist/plugins/claude-code/commands.js +54 -0
- package/dist/plugins/claude-code/commands.js.map +1 -0
- package/dist/plugins/claude-code/index.d.ts +2 -0
- package/dist/plugins/claude-code/index.js +57 -0
- package/dist/plugins/claude-code/index.js.map +1 -0
- package/dist/plugins/cursor/index.d.ts +2 -0
- package/dist/plugins/cursor/index.js +60 -0
- package/dist/plugins/cursor/index.js.map +1 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +16 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/local/index.d.ts +2 -0
- package/dist/plugins/local/index.js +53 -0
- package/dist/plugins/local/index.js.map +1 -0
- package/dist/plugins/local/init-step.d.ts +9 -0
- package/dist/plugins/local/init-step.js +24 -0
- package/dist/plugins/local/init-step.js.map +1 -0
- package/dist/plugins/local/local-spec-provider.d.ts +9 -0
- package/dist/plugins/local/local-spec-provider.js +66 -0
- package/dist/plugins/local/local-spec-provider.js.map +1 -0
- package/dist/plugins/local/local-ticket-provider.d.ts +24 -0
- package/dist/plugins/local/local-ticket-provider.js +89 -0
- package/dist/plugins/local/local-ticket-provider.js.map +1 -0
- package/dist/plugins/none/index.d.ts +2 -0
- package/dist/plugins/none/index.js +78 -0
- package/dist/plugins/none/index.js.map +1 -0
- package/dist/plugins/other-ai/index.d.ts +2 -0
- package/dist/plugins/other-ai/index.js +48 -0
- package/dist/plugins/other-ai/index.js.map +1 -0
- package/dist/plugins/registry.d.ts +4 -0
- package/dist/plugins/registry.js +18 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/resolve.d.ts +8 -0
- package/dist/plugins/resolve.js +23 -0
- package/dist/plugins/resolve.js.map +1 -0
- package/dist/plugins/types.d.ts +36 -0
- package/dist/plugins/types.js +2 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/plugins/vscode-copilot/agents.d.ts +4 -0
- package/dist/plugins/vscode-copilot/agents.js +51 -0
- package/dist/plugins/vscode-copilot/agents.js.map +1 -0
- package/dist/plugins/vscode-copilot/index.d.ts +2 -0
- package/dist/plugins/vscode-copilot/index.js +59 -0
- package/dist/plugins/vscode-copilot/index.js.map +1 -0
- package/dist/plugins/vscode-copilot/prompts.d.ts +4 -0
- package/dist/plugins/vscode-copilot/prompts.js +60 -0
- package/dist/plugins/vscode-copilot/prompts.js.map +1 -0
- package/dist/schemas/config.d.ts +24 -0
- package/dist/schemas/config.js +38 -0
- package/dist/schemas/config.js.map +1 -0
- package/dist/types.d.ts +84 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/confirm.d.ts +7 -0
- package/dist/ui/confirm.js +19 -0
- package/dist/ui/confirm.js.map +1 -0
- package/dist/ui/error-display.d.ts +6 -0
- package/dist/ui/error-display.js +23 -0
- package/dist/ui/error-display.js.map +1 -0
- package/dist/ui/masked-input.d.ts +9 -0
- package/dist/ui/masked-input.js +25 -0
- package/dist/ui/masked-input.js.map +1 -0
- package/dist/ui/multi-select.d.ts +13 -0
- package/dist/ui/multi-select.js +127 -0
- package/dist/ui/multi-select.js.map +1 -0
- package/dist/ui/select-input.d.ts +12 -0
- package/dist/ui/select-input.js +81 -0
- package/dist/ui/select-input.js.map +1 -0
- package/dist/ui/spinner.d.ts +6 -0
- package/dist/ui/spinner.js +18 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/text-input.d.ts +9 -0
- package/dist/ui/text-input.js +23 -0
- package/dist/ui/text-input.js.map +1 -0
- package/dist/wizard/passthrough-step.d.ts +6 -0
- package/dist/wizard/passthrough-step.js +8 -0
- package/dist/wizard/passthrough-step.js.map +1 -0
- package/dist/wizard/plugin-select-step.d.ts +10 -0
- package/dist/wizard/plugin-select-step.js +31 -0
- package/dist/wizard/plugin-select-step.js.map +1 -0
- package/dist/wizard/summary-step.d.ts +2 -0
- package/dist/wizard/summary-step.js +97 -0
- package/dist/wizard/summary-step.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Text, Box, useApp } from 'ink';
|
|
3
|
+
import { useAsync } from '../hooks/use-async.js';
|
|
4
|
+
import Spinner from '../ui/spinner.js';
|
|
5
|
+
import ErrorDisplay from '../ui/error-display.js';
|
|
6
|
+
import { dirExists, listSubdirs } from '../helpers/fs.js';
|
|
7
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
const TICKETS_DIR = '.ai/tickets';
|
|
10
|
+
async function countMdFiles(dir) {
|
|
11
|
+
let count = 0;
|
|
12
|
+
try {
|
|
13
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
if (entry.isFile() && entry.name.endsWith('.md'))
|
|
16
|
+
count++;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
if (error.code === 'ENOENT')
|
|
21
|
+
return 0;
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
return count;
|
|
25
|
+
}
|
|
26
|
+
async function findLatestMtime(baseDir) {
|
|
27
|
+
let latest = null;
|
|
28
|
+
const projects = await listSubdirs(baseDir);
|
|
29
|
+
for (const project of projects) {
|
|
30
|
+
const projectPath = join(baseDir, project);
|
|
31
|
+
try {
|
|
32
|
+
const entries = await readdir(projectPath, { withFileTypes: true });
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
if (!entry.isFile() || !entry.name.endsWith('.md'))
|
|
35
|
+
continue;
|
|
36
|
+
const s = await stat(join(projectPath, entry.name));
|
|
37
|
+
if (s.mtime && (latest === null || s.mtime > latest)) {
|
|
38
|
+
latest = s.mtime;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error.code !== 'ENOENT')
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (latest === null)
|
|
48
|
+
return null;
|
|
49
|
+
const year = latest.getFullYear();
|
|
50
|
+
const month = String(latest.getMonth() + 1).padStart(2, '0');
|
|
51
|
+
const day = String(latest.getDate()).padStart(2, '0');
|
|
52
|
+
const hours = String(latest.getHours()).padStart(2, '0');
|
|
53
|
+
const minutes = String(latest.getMinutes()).padStart(2, '0');
|
|
54
|
+
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
|
55
|
+
}
|
|
56
|
+
async function getStatus() {
|
|
57
|
+
if (!(await dirExists(TICKETS_DIR))) {
|
|
58
|
+
return { projects: [], lastSync: null };
|
|
59
|
+
}
|
|
60
|
+
const projectNames = await listSubdirs(TICKETS_DIR);
|
|
61
|
+
const projects = [];
|
|
62
|
+
for (const project of projectNames) {
|
|
63
|
+
const count = await countMdFiles(join(TICKETS_DIR, project));
|
|
64
|
+
projects.push({ project, count });
|
|
65
|
+
}
|
|
66
|
+
const lastSync = await findLatestMtime(TICKETS_DIR);
|
|
67
|
+
return { projects, lastSync };
|
|
68
|
+
}
|
|
69
|
+
export default function StatusCommand() {
|
|
70
|
+
const { exit } = useApp();
|
|
71
|
+
const { loading, error, result } = useAsync(async () => {
|
|
72
|
+
const data = await getStatus();
|
|
73
|
+
setTimeout(() => {
|
|
74
|
+
exit();
|
|
75
|
+
}, 0);
|
|
76
|
+
return data;
|
|
77
|
+
});
|
|
78
|
+
if (loading)
|
|
79
|
+
return React.createElement(Spinner, { label: "Checking status..." });
|
|
80
|
+
if (error)
|
|
81
|
+
return React.createElement(ErrorDisplay, { error: error });
|
|
82
|
+
if (!result || result.projects.length === 0) {
|
|
83
|
+
return (React.createElement(Text, { dimColor: true }, "No synced tickets found. Run \"hai pull\" first."));
|
|
84
|
+
}
|
|
85
|
+
const total = result.projects.reduce((sum, p) => sum + p.count, 0);
|
|
86
|
+
return (React.createElement(Box, { flexDirection: "column" },
|
|
87
|
+
result.projects.map(p => (React.createElement(Text, { key: p.project },
|
|
88
|
+
p.project,
|
|
89
|
+
": ",
|
|
90
|
+
p.count,
|
|
91
|
+
' ',
|
|
92
|
+
p.count === 1 ? 'ticket' : 'tickets'))),
|
|
93
|
+
React.createElement(Text, { bold: true },
|
|
94
|
+
"Total: ",
|
|
95
|
+
total,
|
|
96
|
+
" ",
|
|
97
|
+
total === 1 ? 'ticket' : 'tickets'),
|
|
98
|
+
React.createElement(Text, null,
|
|
99
|
+
"Last sync: ",
|
|
100
|
+
result.lastSync ?? 'Never')));
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../source/commands/status.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { projectFromKey } from '../helpers/tickets.js';
|
|
2
|
+
const IMAGE_MIME_PREFIXES = ['image/'];
|
|
3
|
+
function formatDate(iso) {
|
|
4
|
+
return iso.slice(0, 10);
|
|
5
|
+
}
|
|
6
|
+
function formatDateTime(iso) {
|
|
7
|
+
const d = new Date(iso);
|
|
8
|
+
const date = iso.slice(0, 10);
|
|
9
|
+
const hours = String(d.getUTCHours()).padStart(2, '0');
|
|
10
|
+
const minutes = String(d.getUTCMinutes()).padStart(2, '0');
|
|
11
|
+
return `${date} ${hours}:${minutes}`;
|
|
12
|
+
}
|
|
13
|
+
function relativeLinkPath(fromKey, toKey) {
|
|
14
|
+
const fromProject = projectFromKey(fromKey);
|
|
15
|
+
const toProject = projectFromKey(toKey);
|
|
16
|
+
if (fromProject === toProject) {
|
|
17
|
+
return `./${toKey}.md`;
|
|
18
|
+
}
|
|
19
|
+
return `../${toProject}/${toKey}.md`;
|
|
20
|
+
}
|
|
21
|
+
function renderLinks(fromKey, links, localFiles) {
|
|
22
|
+
const lines = [];
|
|
23
|
+
lines.push('## Linked Issues');
|
|
24
|
+
lines.push('');
|
|
25
|
+
if (links.length === 0) {
|
|
26
|
+
lines.push('No linked issues.');
|
|
27
|
+
lines.push('');
|
|
28
|
+
return lines;
|
|
29
|
+
}
|
|
30
|
+
for (const link of links) {
|
|
31
|
+
const path = relativeLinkPath(fromKey, link.key);
|
|
32
|
+
const hasFile = localFiles.has(link.key);
|
|
33
|
+
const ref = hasFile ? `[${link.key}](${path})` : link.key;
|
|
34
|
+
lines.push(`- **${link.relation}:** ${ref}`);
|
|
35
|
+
}
|
|
36
|
+
lines.push('');
|
|
37
|
+
return lines;
|
|
38
|
+
}
|
|
39
|
+
export function renderTicket(ticket, options) {
|
|
40
|
+
const lines = [];
|
|
41
|
+
const localFiles = options?.localFiles ?? new Set();
|
|
42
|
+
// Header
|
|
43
|
+
lines.push(`# ${ticket.key}: ${ticket.summary}`);
|
|
44
|
+
lines.push('');
|
|
45
|
+
// Metadata
|
|
46
|
+
lines.push(`- **Status:** ${ticket.status}`);
|
|
47
|
+
lines.push(`- **Assignee:** ${ticket.assignee ?? 'Unassigned'}`);
|
|
48
|
+
lines.push(`- **Priority:** ${ticket.priority}`);
|
|
49
|
+
lines.push(`- **Created:** ${formatDate(ticket.created)}`);
|
|
50
|
+
lines.push(`- **Updated:** ${formatDate(ticket.updated)}`);
|
|
51
|
+
lines.push('');
|
|
52
|
+
// Linked Issues
|
|
53
|
+
if (ticket.links.length > 0) {
|
|
54
|
+
lines.push(...renderLinks(ticket.key, ticket.links, localFiles));
|
|
55
|
+
}
|
|
56
|
+
// Images
|
|
57
|
+
const images = ticket.attachments.filter(a => IMAGE_MIME_PREFIXES.some(p => a.mimeType.startsWith(p)));
|
|
58
|
+
if (images.length > 0) {
|
|
59
|
+
lines.push('## Images');
|
|
60
|
+
lines.push('');
|
|
61
|
+
for (const img of images) {
|
|
62
|
+
lines.push(`- [${img.filename}](${img.content})`);
|
|
63
|
+
}
|
|
64
|
+
lines.push('');
|
|
65
|
+
}
|
|
66
|
+
// Description
|
|
67
|
+
lines.push('## Description');
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(ticket.description.trim() || 'No description.');
|
|
70
|
+
lines.push('');
|
|
71
|
+
// Comments
|
|
72
|
+
lines.push('## Comments');
|
|
73
|
+
lines.push('');
|
|
74
|
+
if (ticket.comments.length === 0) {
|
|
75
|
+
lines.push('No comments.');
|
|
76
|
+
lines.push('');
|
|
77
|
+
return lines.join('\n');
|
|
78
|
+
}
|
|
79
|
+
const sorted = [...ticket.comments].sort((a, b) => new Date(a.created).getTime() - new Date(b.created).getTime());
|
|
80
|
+
for (const comment of sorted) {
|
|
81
|
+
const time = formatDateTime(comment.created);
|
|
82
|
+
lines.push(`### ${comment.author} \u2014 ${time}`);
|
|
83
|
+
lines.push('');
|
|
84
|
+
lines.push(comment.body.trim() || 'No content.');
|
|
85
|
+
lines.push('');
|
|
86
|
+
}
|
|
87
|
+
return lines.join('\n');
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=ticket-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ticket-renderer.js","sourceRoot":"","sources":["../../source/components/ticket-renderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAErD,MAAM,mBAAmB,GAAG,CAAC,QAAQ,CAAC,CAAC;AAEvC,SAAS,UAAU,CAAC,GAAW;IAC9B,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IAClC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3D,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,OAAO,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe,EAAE,KAAa;IACvD,MAAM,WAAW,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IACxC,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,KAAK,KAAK,KAAK,CAAC;IACxB,CAAC;IAED,OAAO,MAAM,SAAS,IAAI,KAAK,KAAK,CAAC;AACtC,CAAC;AAED,SAAS,WAAW,CACnB,OAAe,EACf,KAAmB,EACnB,UAAuB;IAEvB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,KAAK,CAAC;IACd,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAC1D,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,OAAO,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,KAAK,CAAC;AACd,CAAC;AAMD,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,OAAuB;IACnE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAG,OAAO,EAAE,UAAU,IAAI,IAAI,GAAG,EAAU,CAAC;IAE5D,SAAS;IACT,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,GAAG,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACjD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,WAAW;IACX,KAAK,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC7C,KAAK,CAAC,IAAI,CAAC,mBAAmB,MAAM,CAAC,QAAQ,IAAI,YAAY,EAAE,CAAC,CAAC;IACjE,KAAK,CAAC,IAAI,CAAC,mBAAmB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IACjD,KAAK,CAAC,IAAI,CAAC,kBAAkB,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3D,KAAK,CAAC,IAAI,CAAC,kBAAkB,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,gBAAgB;IAChB,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,SAAS;IACT,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAC5C,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CACvD,CAAC;IACF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC;QACnD,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC;IAED,cAAc;IACd,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC7B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,iBAAiB,CAAC,CAAC;IAC3D,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,WAAW;IACX,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC1B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CACvE,CAAC;IACF,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC,OAAO,OAAO,CAAC,MAAM,WAAW,IAAI,EAAE,CAAC,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,aAAa,CAAC,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { HaiConfig } from '../schemas/config.js';
|
|
3
|
+
interface ConfigContextValue {
|
|
4
|
+
config: HaiConfig;
|
|
5
|
+
isEditMode: boolean;
|
|
6
|
+
error: Error | null;
|
|
7
|
+
setConfig: (config: HaiConfig) => void;
|
|
8
|
+
getPluginConfig: <T>(pluginId: string) => T | null;
|
|
9
|
+
saveToFile: (config: HaiConfig) => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
interface ConfigProviderProps {
|
|
12
|
+
isInit: boolean;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export declare function ConfigProvider({ children, isInit }: ConfigProviderProps): React.JSX.Element;
|
|
16
|
+
export declare function useConfigContext(): ConfigContextValue;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react';
|
|
2
|
+
import { Text } from 'ink';
|
|
3
|
+
import { readConfig, writeConfig, configExists } from '../helpers/config.js';
|
|
4
|
+
const ConfigContext = createContext(null);
|
|
5
|
+
export function ConfigProvider({ children, isInit }) {
|
|
6
|
+
const [config, setConfig] = useState(null);
|
|
7
|
+
const [isEditMode, setEditMode] = useState(false);
|
|
8
|
+
const [isConfigRequired, setIsConfigRequired] = useState(false);
|
|
9
|
+
const [error, setError] = useState(null);
|
|
10
|
+
const configRef = useRef(config);
|
|
11
|
+
configRef.current = config;
|
|
12
|
+
const saveToFile = useCallback(async (config) => {
|
|
13
|
+
setError(null);
|
|
14
|
+
try {
|
|
15
|
+
await writeConfig(config);
|
|
16
|
+
setConfig(config);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
20
|
+
}
|
|
21
|
+
}, []);
|
|
22
|
+
const getPluginConfig = useCallback((pluginId) => {
|
|
23
|
+
if (!config)
|
|
24
|
+
return null;
|
|
25
|
+
const entry = config.plugins.find(p => p.plugin === pluginId);
|
|
26
|
+
if (!entry)
|
|
27
|
+
return null;
|
|
28
|
+
return entry;
|
|
29
|
+
}, [config]);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
configExists().then(async (exists) => {
|
|
32
|
+
try {
|
|
33
|
+
const result = exists
|
|
34
|
+
? await readConfig()
|
|
35
|
+
: { plugins: [] };
|
|
36
|
+
setConfig(result);
|
|
37
|
+
if (exists) {
|
|
38
|
+
setEditMode(true);
|
|
39
|
+
}
|
|
40
|
+
else if (!isInit) {
|
|
41
|
+
setIsConfigRequired(true);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}, [isInit]);
|
|
49
|
+
const value = useMemo(() => ({
|
|
50
|
+
config: config,
|
|
51
|
+
error,
|
|
52
|
+
isEditMode,
|
|
53
|
+
setConfig,
|
|
54
|
+
saveToFile,
|
|
55
|
+
getPluginConfig,
|
|
56
|
+
}), [config, error, saveToFile, getPluginConfig, isEditMode]);
|
|
57
|
+
if (error) {
|
|
58
|
+
return (React.createElement(Text, { color: "red" },
|
|
59
|
+
"Error loading configuration: ",
|
|
60
|
+
error.message));
|
|
61
|
+
}
|
|
62
|
+
if (isConfigRequired) {
|
|
63
|
+
return (React.createElement(Text, { color: "red" }, "Configuration file not found. Please run 'init' to create one."));
|
|
64
|
+
}
|
|
65
|
+
if (!config) {
|
|
66
|
+
return React.createElement(Text, null, "Loading configuration...");
|
|
67
|
+
}
|
|
68
|
+
return (React.createElement(ConfigContext.Provider, { value: value }, children));
|
|
69
|
+
}
|
|
70
|
+
export function useConfigContext() {
|
|
71
|
+
const ctx = useContext(ConfigContext);
|
|
72
|
+
if (!ctx) {
|
|
73
|
+
throw new Error('useConfigContext must be used within a ConfigProvider');
|
|
74
|
+
}
|
|
75
|
+
return ctx;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=config-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-context.js","sourceRoot":"","sources":["../../source/contexts/config-context.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface ErrorContextValue {
|
|
3
|
+
error: Error | null;
|
|
4
|
+
setError: (error: Error) => void;
|
|
5
|
+
clearError: () => void;
|
|
6
|
+
}
|
|
7
|
+
interface ErrorProviderProps {
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare function ErrorProvider({ children }: ErrorProviderProps): React.JSX.Element;
|
|
11
|
+
export declare function useErrorContext(): ErrorContextValue;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { createContext, useCallback, useContext, useMemo, useState, } from 'react';
|
|
2
|
+
import ErrorDisplay from '../ui/error-display.js';
|
|
3
|
+
const ErrorContext = createContext(null);
|
|
4
|
+
export function ErrorProvider({ children }) {
|
|
5
|
+
const [error, setErrorState] = useState(null);
|
|
6
|
+
const setError = useCallback((err) => {
|
|
7
|
+
setErrorState(err);
|
|
8
|
+
}, []);
|
|
9
|
+
const clearError = useCallback(() => {
|
|
10
|
+
setErrorState(null);
|
|
11
|
+
}, []);
|
|
12
|
+
const value = useMemo(() => ({ error, setError, clearError }), [error, setError, clearError]);
|
|
13
|
+
try {
|
|
14
|
+
return (React.createElement(ErrorContext.Provider, { value: value }, error ? React.createElement(ErrorDisplay, { error: error }) : children));
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
return (React.createElement(ErrorContext.Provider, { value: value },
|
|
18
|
+
React.createElement(ErrorDisplay, { error: e instanceof Error ? e : new Error(String(e)) })));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function useErrorContext() {
|
|
22
|
+
const ctx = useContext(ErrorContext);
|
|
23
|
+
if (!ctx) {
|
|
24
|
+
throw new Error('useErrorContext must be used within an ErrorProvider');
|
|
25
|
+
}
|
|
26
|
+
return ctx;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=error-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-context.js","sourceRoot":"","sources":["../../source/contexts/error-context.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,OAAO,EACP,QAAQ,GACR,MAAM,OAAO,CAAC;AACf,OAAO,YAAY,MAAM,wBAAwB,CAAC;AAQlD,MAAM,YAAY,GAAG,aAAa,CAA2B,IAAI,CAAC,CAAC;AAMnE,MAAM,UAAU,aAAa,CAAC,EAAC,QAAQ,EAAqB;IAC3D,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC;IAE5D,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,GAAU,EAAE,EAAE;QAC3C,aAAa,CAAC,GAAG,CAAC,CAAC;IACpB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,aAAa,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,KAAK,GAAG,OAAO,CACpB,GAAG,EAAE,CAAC,CAAC,EAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAC,CAAC,EACrC,CAAC,KAAK,EAAE,QAAQ,EAAE,UAAU,CAAC,CAC7B,CAAC;IAEF,IAAI,CAAC;QACJ,OAAO,CACN,oBAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,IACjC,KAAK,CAAC,CAAC,CAAC,oBAAC,YAAY,IAAC,KAAK,EAAE,KAAK,GAAI,CAAC,CAAC,CAAC,QAAQ,CAC3B,CACxB,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,OAAO,CACN,oBAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK;YAClC,oBAAC,YAAY,IACZ,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GACnD,CACqB,CACxB,CAAC;IACH,CAAC;AACF,CAAC;AAED,MAAM,UAAU,eAAe;IAC9B,MAAM,GAAG,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,GAAG,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { HaiConfig } from '../schemas/config.js';
|
|
2
|
+
export declare function readConfig(path?: string): Promise<HaiConfig>;
|
|
3
|
+
export declare function writeConfig(config: HaiConfig, path?: string): Promise<void>;
|
|
4
|
+
export declare function configExists(path?: string): Promise<boolean>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { readJsonFile, writeJsonFile, fileExists } from './fs.js';
|
|
3
|
+
import { HaiConfigSchema } from '../schemas/config.js';
|
|
4
|
+
const DEFAULT_CONFIG_FILENAME = 'hai.json';
|
|
5
|
+
function defaultPath(path) {
|
|
6
|
+
return path ?? join(process.cwd(), DEFAULT_CONFIG_FILENAME);
|
|
7
|
+
}
|
|
8
|
+
export async function readConfig(path) {
|
|
9
|
+
const filePath = defaultPath(path);
|
|
10
|
+
let data;
|
|
11
|
+
try {
|
|
12
|
+
data = await readJsonFile(filePath);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (error.code === 'ENOENT') {
|
|
16
|
+
throw new Error(`Config file not found: ${filePath}`);
|
|
17
|
+
}
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
return HaiConfigSchema.parse(data);
|
|
21
|
+
}
|
|
22
|
+
export async function writeConfig(config, path) {
|
|
23
|
+
const filePath = defaultPath(path);
|
|
24
|
+
await writeJsonFile(filePath, config);
|
|
25
|
+
}
|
|
26
|
+
export async function configExists(path) {
|
|
27
|
+
return fileExists(defaultPath(path));
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../source/helpers/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAC,MAAM,WAAW,CAAC;AAC/B,OAAO,EAAC,YAAY,EAAE,aAAa,EAAE,UAAU,EAAC,MAAM,SAAS,CAAC;AAChE,OAAO,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAC;AAGrD,MAAM,uBAAuB,GAAG,UAAU,CAAC;AAE3C,SAAS,WAAW,CAAC,IAAa;IACjC,OAAO,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,uBAAuB,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAa;IAC7C,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAEnC,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACJ,IAAI,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACzB,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,KAAK,CAAC;IACb,CAAC;IAED,OAAO,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,MAAiB,EACjB,IAAa;IAEb,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAa;IAC/C,OAAO,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function readJsonFile(path: string): Promise<unknown>;
|
|
2
|
+
export declare function readJsonFileSafe(path: string): Promise<Record<string, unknown>>;
|
|
3
|
+
export declare function writeJsonFile(path: string, data: unknown): Promise<void>;
|
|
4
|
+
export declare function fileExists(path: string): Promise<boolean>;
|
|
5
|
+
export declare function dirExists(path: string): Promise<boolean>;
|
|
6
|
+
export declare function ensureDir(path: string): Promise<void>;
|
|
7
|
+
export declare function walkMdFiles(dir: string): AsyncGenerator<string>;
|
|
8
|
+
export declare function listSubdirs(dir: string): Promise<string[]>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { readFile, writeFile, stat, readdir, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
export async function readJsonFile(path) {
|
|
4
|
+
const text = await readFile(path, 'utf-8');
|
|
5
|
+
return JSON.parse(text);
|
|
6
|
+
}
|
|
7
|
+
export async function readJsonFileSafe(path) {
|
|
8
|
+
try {
|
|
9
|
+
const text = await readFile(path, 'utf-8');
|
|
10
|
+
if (!text.trim())
|
|
11
|
+
return {};
|
|
12
|
+
return JSON.parse(text);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
if (error.code === 'ENOENT')
|
|
16
|
+
return {};
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export async function writeJsonFile(path, data) {
|
|
21
|
+
await writeFile(path, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
22
|
+
}
|
|
23
|
+
export async function fileExists(path) {
|
|
24
|
+
try {
|
|
25
|
+
const s = await stat(path);
|
|
26
|
+
return s.isFile();
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
if (error.code === 'ENOENT')
|
|
30
|
+
return false;
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function dirExists(path) {
|
|
35
|
+
try {
|
|
36
|
+
const s = await stat(path);
|
|
37
|
+
return s.isDirectory();
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error.code === 'ENOENT')
|
|
41
|
+
return false;
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function ensureDir(path) {
|
|
46
|
+
await mkdir(path, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
export async function* walkMdFiles(dir) {
|
|
49
|
+
let entries;
|
|
50
|
+
try {
|
|
51
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (error.code === 'ENOENT')
|
|
55
|
+
return;
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
for (const entry of entries) {
|
|
59
|
+
const fullPath = join(dir, entry.name);
|
|
60
|
+
if (entry.isDirectory()) {
|
|
61
|
+
yield* walkMdFiles(fullPath);
|
|
62
|
+
}
|
|
63
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
64
|
+
yield fullPath;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export async function listSubdirs(dir) {
|
|
69
|
+
let entries;
|
|
70
|
+
try {
|
|
71
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (error.code === 'ENOENT')
|
|
75
|
+
return [];
|
|
76
|
+
throw error;
|
|
77
|
+
}
|
|
78
|
+
return entries
|
|
79
|
+
.filter(e => e.isDirectory())
|
|
80
|
+
.map(e => e.name)
|
|
81
|
+
.sort();
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../source/helpers/fs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ensureGitignoreEntries, runPreflightChecks, } from '../helpers/preflight.js';
|
|
2
|
+
import { ensureDir } from '../helpers/fs.js';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { resolveAiProvider } from '../plugins/resolve.js';
|
|
5
|
+
import { pullAll } from '../helpers/pull.js';
|
|
6
|
+
export async function initializeEnvironment(config) {
|
|
7
|
+
await runPreflightChecks({
|
|
8
|
+
gitIgnoreEntriesMustBeSatisfied: false
|
|
9
|
+
});
|
|
10
|
+
const cwd = process.cwd();
|
|
11
|
+
await ensureDir(join(cwd, '.ai', 'tickets'));
|
|
12
|
+
await ensureDir(join(cwd, '.ai', 'specs'));
|
|
13
|
+
const aiProvider = resolveAiProvider(config);
|
|
14
|
+
await aiProvider.install(cwd);
|
|
15
|
+
await ensureGitignoreEntries();
|
|
16
|
+
await pullAll(config);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../source/helpers/init.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,sBAAsB,EACtB,kBAAkB,GAClB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG7C,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,MAAiB;IAC5D,MAAM,kBAAkB,CAAC;QACxB,+BAA+B,EAAE,KAAK;KACtC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1B,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;IAC7C,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAE3C,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAE9B,MAAM,sBAAsB,EAAE,CAAC;IAE/B,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function assertGitRoot(): Promise<void>;
|
|
2
|
+
export declare function ensureGitignoreEntries(): Promise<void>;
|
|
3
|
+
interface PrflightChecks {
|
|
4
|
+
mustBeInGit?: boolean;
|
|
5
|
+
gitIgnoreEntriesMustBeSatisfied?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function runPreflightChecks({ mustBeInGit, gitIgnoreEntriesMustBeSatisfied }?: PrflightChecks): Promise<void>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { dirExists } from './fs.js';
|
|
4
|
+
const REQUIRED_GITIGNORE_ENTRIES = ['hai.json', '.ai'];
|
|
5
|
+
export async function assertGitRoot() {
|
|
6
|
+
const cwd = process.cwd();
|
|
7
|
+
if (!(await dirExists(join(cwd, '.git')))) {
|
|
8
|
+
throw new Error('hai must be run from the root of a git repository (.git not found in current directory).');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function parseGitignoreEntries(content) {
|
|
12
|
+
return new Set(content
|
|
13
|
+
.split('\n')
|
|
14
|
+
.map(l => l.trim())
|
|
15
|
+
.filter(l => l && !l.startsWith('#')));
|
|
16
|
+
}
|
|
17
|
+
export async function ensureGitignoreEntries() {
|
|
18
|
+
const cwd = process.cwd();
|
|
19
|
+
const gitignorePath = join(cwd, '.gitignore');
|
|
20
|
+
let content;
|
|
21
|
+
try {
|
|
22
|
+
content = await readFile(gitignorePath, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
if (error.code === 'ENOENT') {
|
|
26
|
+
content = '';
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const entries = parseGitignoreEntries(content);
|
|
33
|
+
const missing = [];
|
|
34
|
+
for (const entry of REQUIRED_GITIGNORE_ENTRIES) {
|
|
35
|
+
const found = entries.has(entry) || entries.has(`/${entry}`);
|
|
36
|
+
if (!found)
|
|
37
|
+
missing.push(entry);
|
|
38
|
+
}
|
|
39
|
+
if (missing.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
const suffix = missing.join('\n') + '\n';
|
|
42
|
+
const updated = content.endsWith('\n') || content === ''
|
|
43
|
+
? content + suffix
|
|
44
|
+
: content + '\n' + suffix;
|
|
45
|
+
await writeFile(gitignorePath, updated, 'utf-8');
|
|
46
|
+
}
|
|
47
|
+
function isFlagSet(flag) {
|
|
48
|
+
return flag === undefined || flag === true;
|
|
49
|
+
}
|
|
50
|
+
export async function runPreflightChecks({ mustBeInGit, gitIgnoreEntriesMustBeSatisfied } = {}) {
|
|
51
|
+
if (isFlagSet(mustBeInGit)) {
|
|
52
|
+
await assertGitRoot();
|
|
53
|
+
}
|
|
54
|
+
if (!isFlagSet(gitIgnoreEntriesMustBeSatisfied)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const cwd = process.cwd();
|
|
58
|
+
const gitignorePath = join(cwd, '.gitignore');
|
|
59
|
+
let gitignoreContent;
|
|
60
|
+
try {
|
|
61
|
+
gitignoreContent = await readFile(gitignorePath, 'utf-8');
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error.code === 'ENOENT') {
|
|
65
|
+
throw new Error('hai.json must be listed in .gitignore but no .gitignore file was found.');
|
|
66
|
+
}
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
const entries = parseGitignoreEntries(gitignoreContent);
|
|
70
|
+
for (const required of REQUIRED_GITIGNORE_ENTRIES) {
|
|
71
|
+
const found = entries.has(required) || entries.has(`/${required}`);
|
|
72
|
+
if (!found) {
|
|
73
|
+
throw new Error(`"${required}" must be listed in .gitignore. Run "hai configure" to fix this automatically.`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../source/helpers/preflight.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HaiConfig } from '../schemas/config.js';
|
|
2
|
+
type PullOptions = {
|
|
3
|
+
dryRun?: boolean;
|
|
4
|
+
updateLocal?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function pullTickets(config: HaiConfig, options?: PullOptions): Promise<void>;
|
|
7
|
+
export declare function pullSpecs(config: HaiConfig, options?: PullOptions): Promise<void>;
|
|
8
|
+
export declare function pullAll(config: HaiConfig, options?: PullOptions): Promise<void>;
|
|
9
|
+
export {};
|