@uzukko/agentpm 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/bin/taskapp.js +2 -0
- package/dist/api-client.d.ts +2 -0
- package/dist/api-client.js +27 -0
- package/dist/api-client.js.map +1 -0
- package/dist/commands/activity.d.ts +2 -0
- package/dist/commands/activity.js +88 -0
- package/dist/commands/activity.js.map +1 -0
- package/dist/commands/ball.d.ts +2 -0
- package/dist/commands/ball.js +69 -0
- package/dist/commands/ball.js.map +1 -0
- package/dist/commands/client.d.ts +2 -0
- package/dist/commands/client.js +149 -0
- package/dist/commands/client.js.map +1 -0
- package/dist/commands/config-cmd.d.ts +2 -0
- package/dist/commands/config-cmd.js +95 -0
- package/dist/commands/config-cmd.js.map +1 -0
- package/dist/commands/meeting.d.ts +2 -0
- package/dist/commands/meeting.js +100 -0
- package/dist/commands/meeting.js.map +1 -0
- package/dist/commands/milestone.d.ts +2 -0
- package/dist/commands/milestone.js +98 -0
- package/dist/commands/milestone.js.map +1 -0
- package/dist/commands/minutes.d.ts +2 -0
- package/dist/commands/minutes.js +62 -0
- package/dist/commands/minutes.js.map +1 -0
- package/dist/commands/review.d.ts +2 -0
- package/dist/commands/review.js +98 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/scheduling.d.ts +2 -0
- package/dist/commands/scheduling.js +184 -0
- package/dist/commands/scheduling.js.map +1 -0
- package/dist/commands/space.d.ts +2 -0
- package/dist/commands/space.js +69 -0
- package/dist/commands/space.js.map +1 -0
- package/dist/commands/task.d.ts +2 -0
- package/dist/commands/task.js +192 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/commands/wiki.d.ts +2 -0
- package/dist/commands/wiki.js +121 -0
- package/dist/commands/wiki.js.map +1 -0
- package/dist/config.d.ts +8 -0
- package/dist/config.js +41 -0
- package/dist/config.js.map +1 -0
- package/dist/defaults.d.ts +4 -0
- package/dist/defaults.js +8 -0
- package/dist/defaults.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/output.d.ts +2 -0
- package/dist/output.js +140 -0
- package/dist/output.js.map +1 -0
- package/package.json +31 -0
- package/src/api-client.ts +32 -0
- package/src/commands/activity.ts +83 -0
- package/src/commands/ball.ts +64 -0
- package/src/commands/client.ts +135 -0
- package/src/commands/config-cmd.ts +106 -0
- package/src/commands/meeting.ts +91 -0
- package/src/commands/milestone.ts +89 -0
- package/src/commands/minutes.ts +57 -0
- package/src/commands/review.ts +89 -0
- package/src/commands/scheduling.ts +171 -0
- package/src/commands/space.ts +62 -0
- package/src/commands/task.ts +179 -0
- package/src/commands/wiki.ts +110 -0
- package/src/config.ts +56 -0
- package/src/index.ts +51 -0
- package/src/output.ts +139 -0
- package/tsconfig.json +19 -0
package/src/config.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { setApiConfig } from './api-client.js'
|
|
5
|
+
|
|
6
|
+
const CONFIG_PATH = join(homedir(), '.taskapprc.json')
|
|
7
|
+
|
|
8
|
+
interface CliConfig {
|
|
9
|
+
apiUrl?: string
|
|
10
|
+
apiKey?: string
|
|
11
|
+
defaultSpaceId?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getConfigPath(): string {
|
|
15
|
+
return CONFIG_PATH
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function loadCliConfig(cliOpts: {
|
|
19
|
+
apiKey?: string
|
|
20
|
+
spaceId?: string
|
|
21
|
+
}): void {
|
|
22
|
+
let fileConfig: CliConfig = {}
|
|
23
|
+
if (existsSync(CONFIG_PATH)) {
|
|
24
|
+
try {
|
|
25
|
+
fileConfig = JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'))
|
|
26
|
+
} catch {
|
|
27
|
+
// ignore invalid config file
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Priority: CLI flags > env vars > config file
|
|
32
|
+
const apiUrl = process.env.TASKAPP_API_URL || fileConfig.apiUrl
|
|
33
|
+
const apiKey = cliOpts.apiKey || process.env.TASKAPP_API_KEY || fileConfig.apiKey
|
|
34
|
+
|
|
35
|
+
if (!apiUrl || !apiKey) {
|
|
36
|
+
console.error('Error: Not configured. Run: agentpm login')
|
|
37
|
+
process.exit(1)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setApiConfig(apiUrl, apiKey)
|
|
41
|
+
|
|
42
|
+
// Set space ID for resolveSpaceId
|
|
43
|
+
const spaceId = cliOpts.spaceId || process.env.TASKAPP_SPACE_ID || fileConfig.defaultSpaceId
|
|
44
|
+
if (spaceId) {
|
|
45
|
+
process.env.TASKAPP_SPACE_ID = spaceId
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function resolveSpaceId(opts: { spaceId?: string }): string {
|
|
50
|
+
const spaceId = opts.spaceId || process.env.TASKAPP_SPACE_ID
|
|
51
|
+
if (!spaceId) {
|
|
52
|
+
console.error('Error: --space-id is required (or set TASKAPP_SPACE_ID / defaultSpaceId in ~/.taskapprc.json)')
|
|
53
|
+
process.exit(1)
|
|
54
|
+
}
|
|
55
|
+
return spaceId
|
|
56
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { loadCliConfig } from './config.js'
|
|
3
|
+
import { registerTaskCommands } from './commands/task.js'
|
|
4
|
+
import { registerBallCommands } from './commands/ball.js'
|
|
5
|
+
import { registerMeetingCommands } from './commands/meeting.js'
|
|
6
|
+
import { registerReviewCommands } from './commands/review.js'
|
|
7
|
+
import { registerMilestoneCommands } from './commands/milestone.js'
|
|
8
|
+
import { registerSpaceCommands } from './commands/space.js'
|
|
9
|
+
import { registerActivityCommands } from './commands/activity.js'
|
|
10
|
+
import { registerClientCommands } from './commands/client.js'
|
|
11
|
+
import { registerWikiCommands } from './commands/wiki.js'
|
|
12
|
+
import { registerMinutesCommands } from './commands/minutes.js'
|
|
13
|
+
import { registerSchedulingCommands } from './commands/scheduling.js'
|
|
14
|
+
import { registerConfigCommand } from './commands/config-cmd.js'
|
|
15
|
+
|
|
16
|
+
const program = new Command()
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.name('agentpm')
|
|
20
|
+
.version('0.1.0')
|
|
21
|
+
.description('AgentPM CLI - AI-first task management')
|
|
22
|
+
.option('--json', 'Output raw JSON')
|
|
23
|
+
.option('-s, --space-id <uuid>', 'Override default space ID')
|
|
24
|
+
.option('--api-key <key>', 'Override API key')
|
|
25
|
+
.hook('preAction', (thisCommand, actionCommand) => {
|
|
26
|
+
// Walk up to find the root command name (handles nested subcommands)
|
|
27
|
+
let cmd = actionCommand
|
|
28
|
+
while (cmd.parent && cmd.parent !== thisCommand) {
|
|
29
|
+
cmd = cmd.parent
|
|
30
|
+
}
|
|
31
|
+
// config/login subcommands don't need auth
|
|
32
|
+
if (cmd.name() === 'config' || cmd.name() === 'login') return
|
|
33
|
+
|
|
34
|
+
const opts = thisCommand.opts()
|
|
35
|
+
loadCliConfig({ apiKey: opts.apiKey, spaceId: opts.spaceId })
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
registerTaskCommands(program)
|
|
39
|
+
registerBallCommands(program)
|
|
40
|
+
registerMeetingCommands(program)
|
|
41
|
+
registerReviewCommands(program)
|
|
42
|
+
registerMilestoneCommands(program)
|
|
43
|
+
registerSpaceCommands(program)
|
|
44
|
+
registerActivityCommands(program)
|
|
45
|
+
registerClientCommands(program)
|
|
46
|
+
registerWikiCommands(program)
|
|
47
|
+
registerMinutesCommands(program)
|
|
48
|
+
registerSchedulingCommands(program)
|
|
49
|
+
registerConfigCommand(program)
|
|
50
|
+
|
|
51
|
+
program.parseAsync()
|
package/src/output.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import chalk from 'chalk'
|
|
2
|
+
import Table from 'cli-table3'
|
|
3
|
+
|
|
4
|
+
export function output(data: unknown, jsonMode: boolean): void {
|
|
5
|
+
if (jsonMode) {
|
|
6
|
+
console.log(JSON.stringify(data, null, 2))
|
|
7
|
+
} else {
|
|
8
|
+
if (Array.isArray(data)) {
|
|
9
|
+
printTable(data)
|
|
10
|
+
} else if (data && typeof data === 'object') {
|
|
11
|
+
const obj = data as Record<string, unknown>
|
|
12
|
+
const entries = Object.entries(obj)
|
|
13
|
+
|
|
14
|
+
// Display all array-of-objects properties as tables
|
|
15
|
+
for (const [key, value] of entries) {
|
|
16
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'object' && value[0] !== null) {
|
|
17
|
+
console.log(chalk.bold(`${key}:`))
|
|
18
|
+
printTable(value as Record<string, unknown>[])
|
|
19
|
+
console.log()
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Print remaining non-array-of-objects values
|
|
24
|
+
for (const [key, value] of entries) {
|
|
25
|
+
if (Array.isArray(value) && value.length > 0 && typeof value[0] === 'object' && value[0] !== null) {
|
|
26
|
+
continue // already printed as table
|
|
27
|
+
}
|
|
28
|
+
if (value === null || value === undefined) continue
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
console.log(`${chalk.gray(key)}: ${value.map(v => String(v)).join(', ')}`)
|
|
31
|
+
} else if (typeof value === 'object') {
|
|
32
|
+
console.log(`${chalk.gray(key)}: ${JSON.stringify(value, null, 2)}`)
|
|
33
|
+
} else {
|
|
34
|
+
console.log(`${chalk.gray(key)}: ${formatValue(key, value)}`)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} else {
|
|
38
|
+
console.log(data)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function printTable(rows: unknown[]): void {
|
|
44
|
+
if (rows.length === 0) {
|
|
45
|
+
console.log(chalk.gray('(no results)'))
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Collect scalar keys from ALL rows (preserving insertion order from first occurrence)
|
|
50
|
+
const seen = new Set<string>()
|
|
51
|
+
const keys: string[] = []
|
|
52
|
+
for (const row of rows) {
|
|
53
|
+
const r = row as Record<string, unknown>
|
|
54
|
+
for (const k of Object.keys(r)) {
|
|
55
|
+
if (seen.has(k)) continue
|
|
56
|
+
seen.add(k)
|
|
57
|
+
// Include only scalar-ish columns (skip nested objects/arrays)
|
|
58
|
+
const v = r[k]
|
|
59
|
+
if (v === null || v === undefined || typeof v !== 'object' || v instanceof Date) {
|
|
60
|
+
keys.push(k)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Limit columns for readability
|
|
66
|
+
const displayKeys = keys.slice(0, 8)
|
|
67
|
+
|
|
68
|
+
const table = new Table({
|
|
69
|
+
head: displayKeys.map((k) => chalk.cyan(k)),
|
|
70
|
+
style: { head: [], border: [] },
|
|
71
|
+
wordWrap: true,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
for (const row of rows) {
|
|
75
|
+
const r = row as Record<string, unknown>
|
|
76
|
+
table.push(displayKeys.map((k) => {
|
|
77
|
+
const v = r[k]
|
|
78
|
+
return formatValue(k, v)
|
|
79
|
+
}))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(table.toString())
|
|
83
|
+
console.log(chalk.gray(`${rows.length} row(s)`))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function formatValue(key: string, value: unknown): string {
|
|
87
|
+
if (value === null || value === undefined) return chalk.gray('-')
|
|
88
|
+
if (typeof value === 'string') {
|
|
89
|
+
// Status coloring
|
|
90
|
+
if (key === 'status' || key === 'ball') {
|
|
91
|
+
return colorStatus(value)
|
|
92
|
+
}
|
|
93
|
+
// Truncate long strings
|
|
94
|
+
if (value.length > 50) return value.slice(0, 47) + '...'
|
|
95
|
+
return value
|
|
96
|
+
}
|
|
97
|
+
if (typeof value === 'number') return chalk.yellow(String(value))
|
|
98
|
+
if (typeof value === 'boolean') return value ? chalk.green('true') : chalk.red('false')
|
|
99
|
+
return String(value)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function colorStatus(status: string): string {
|
|
103
|
+
switch (status) {
|
|
104
|
+
case 'done':
|
|
105
|
+
case 'approved':
|
|
106
|
+
case 'confirmed':
|
|
107
|
+
case 'accepted':
|
|
108
|
+
return chalk.green(status)
|
|
109
|
+
case 'in_progress':
|
|
110
|
+
case 'in_review':
|
|
111
|
+
case 'open':
|
|
112
|
+
case 'internal':
|
|
113
|
+
return chalk.blue(status)
|
|
114
|
+
case 'backlog':
|
|
115
|
+
case 'todo':
|
|
116
|
+
case 'planned':
|
|
117
|
+
case 'pending':
|
|
118
|
+
return chalk.yellow(status)
|
|
119
|
+
case 'considering':
|
|
120
|
+
return chalk.magenta(status)
|
|
121
|
+
case 'cancelled':
|
|
122
|
+
case 'expired':
|
|
123
|
+
case 'changes_requested':
|
|
124
|
+
case 'client':
|
|
125
|
+
return chalk.red(status)
|
|
126
|
+
default:
|
|
127
|
+
return status
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function outputError(error: unknown, jsonMode: boolean): void {
|
|
132
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
133
|
+
if (jsonMode) {
|
|
134
|
+
console.error(JSON.stringify({ error: message }))
|
|
135
|
+
} else {
|
|
136
|
+
console.error(chalk.red(`Error: ${message}`))
|
|
137
|
+
}
|
|
138
|
+
process.exit(1)
|
|
139
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"strict": true,
|
|
10
|
+
"esModuleInterop": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"resolveJsonModule": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|