prjct-cli 0.49.0 → 0.50.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/CHANGELOG.md +18 -0
- package/core/utils/output.ts +113 -5
- package/dist/bin/prjct.mjs +89 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.50.0] - 2026-01-30
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
- Unified output system with new methods - PRJ-130 (#76)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [0.50.0] - 2026-01-30
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Unified output system with new methods** (PRJ-130)
|
|
15
|
+
- Added `ICONS` constant for centralized icon definitions
|
|
16
|
+
- New methods: `info()`, `debug()`, `success()`, `list()`, `table()`, `box()`
|
|
17
|
+
- `debug()` only shows output when `DEBUG=1`
|
|
18
|
+
- Refactored existing methods to use `ICONS` for consistency
|
|
19
|
+
|
|
20
|
+
|
|
3
21
|
## [0.49.0] - 2026-01-30
|
|
4
22
|
|
|
5
23
|
### Features
|
package/core/utils/output.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Unified Output System for prjct-cli
|
|
3
3
|
* Spinner while working → Single line result
|
|
4
4
|
* With prjct branding
|
|
5
5
|
*
|
|
6
6
|
* Supports --quiet mode for CI/CD and scripting
|
|
7
|
+
*
|
|
8
|
+
* @see PRJ-130
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
11
|
import chalk from 'chalk'
|
|
@@ -14,6 +16,22 @@ import { getError } from './error-messages'
|
|
|
14
16
|
const _FRAMES = branding.spinner.frames
|
|
15
17
|
const SPEED = branding.spinner.speed
|
|
16
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Centralized icons for consistent output
|
|
21
|
+
*/
|
|
22
|
+
export const ICONS = {
|
|
23
|
+
success: chalk.green('✓'),
|
|
24
|
+
fail: chalk.red('✗'),
|
|
25
|
+
warn: chalk.yellow('⚠'),
|
|
26
|
+
info: chalk.blue('ℹ'),
|
|
27
|
+
debug: chalk.dim('🔧'),
|
|
28
|
+
bullet: chalk.dim('•'),
|
|
29
|
+
arrow: chalk.dim('→'),
|
|
30
|
+
check: chalk.green('✓'),
|
|
31
|
+
cross: chalk.red('✗'),
|
|
32
|
+
spinner: chalk.cyan('◐'),
|
|
33
|
+
} as const
|
|
34
|
+
|
|
17
35
|
let interval: ReturnType<typeof setInterval> | null = null
|
|
18
36
|
let frame = 0
|
|
19
37
|
|
|
@@ -57,6 +75,12 @@ interface Output {
|
|
|
57
75
|
fail(msg: string): Output
|
|
58
76
|
failWithHint(error: ErrorWithHint | ErrorCode): Output
|
|
59
77
|
warn(msg: string): Output
|
|
78
|
+
info(msg: string): Output
|
|
79
|
+
debug(msg: string): Output
|
|
80
|
+
success(msg: string, metrics?: OutputMetrics): Output
|
|
81
|
+
list(items: string[], options?: { bullet?: string; indent?: number }): Output
|
|
82
|
+
table(rows: Array<Record<string, string | number>>, options?: { header?: boolean }): Output
|
|
83
|
+
box(title: string, content: string): Output
|
|
60
84
|
stop(): Output
|
|
61
85
|
step(current: number, total: number, msg: string): Output
|
|
62
86
|
progress(current: number, total: number, msg?: string): Output
|
|
@@ -99,7 +123,7 @@ const out: Output = {
|
|
|
99
123
|
suffix = chalk.dim(` [${parts.join(' | ')}]`)
|
|
100
124
|
}
|
|
101
125
|
}
|
|
102
|
-
console.log(`${
|
|
126
|
+
console.log(`${ICONS.success} ${truncate(msg, 50)}${suffix}`)
|
|
103
127
|
}
|
|
104
128
|
return this
|
|
105
129
|
},
|
|
@@ -107,7 +131,7 @@ const out: Output = {
|
|
|
107
131
|
// Errors go to stderr even in quiet mode
|
|
108
132
|
fail(msg: string) {
|
|
109
133
|
this.stop()
|
|
110
|
-
console.error(`${
|
|
134
|
+
console.error(`${ICONS.fail} ${truncate(msg, 65)}`)
|
|
111
135
|
return this
|
|
112
136
|
},
|
|
113
137
|
|
|
@@ -116,7 +140,7 @@ const out: Output = {
|
|
|
116
140
|
this.stop()
|
|
117
141
|
const err = typeof error === 'string' ? getError(error) : error
|
|
118
142
|
console.error()
|
|
119
|
-
console.error(`${
|
|
143
|
+
console.error(`${ICONS.fail} ${err.message}`)
|
|
120
144
|
if (err.file) {
|
|
121
145
|
console.error(chalk.dim(` File: ${err.file}`))
|
|
122
146
|
}
|
|
@@ -132,7 +156,91 @@ const out: Output = {
|
|
|
132
156
|
|
|
133
157
|
warn(msg: string) {
|
|
134
158
|
this.stop()
|
|
135
|
-
if (!quietMode) console.log(`${
|
|
159
|
+
if (!quietMode) console.log(`${ICONS.warn} ${truncate(msg, 65)}`)
|
|
160
|
+
return this
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
// Informational message
|
|
164
|
+
info(msg: string) {
|
|
165
|
+
this.stop()
|
|
166
|
+
if (!quietMode) console.log(`${ICONS.info} ${msg}`)
|
|
167
|
+
return this
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
// Debug message (only if DEBUG=1 or DEBUG=true)
|
|
171
|
+
debug(msg: string) {
|
|
172
|
+
this.stop()
|
|
173
|
+
const debugEnabled = process.env.DEBUG === '1' || process.env.DEBUG === 'true'
|
|
174
|
+
if (!quietMode && debugEnabled) {
|
|
175
|
+
console.log(`${ICONS.debug} ${chalk.dim(msg)}`)
|
|
176
|
+
}
|
|
177
|
+
return this
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
// Alias for done - explicit success indicator
|
|
181
|
+
success(msg: string, metrics?: OutputMetrics) {
|
|
182
|
+
return this.done(msg, metrics)
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
// Bulleted list
|
|
186
|
+
list(items: string[], options: { bullet?: string; indent?: number } = {}) {
|
|
187
|
+
this.stop()
|
|
188
|
+
if (quietMode) return this
|
|
189
|
+
const bullet = options.bullet || ICONS.bullet
|
|
190
|
+
const indent = ' '.repeat(options.indent || 0)
|
|
191
|
+
for (const item of items) {
|
|
192
|
+
console.log(`${indent}${bullet} ${item}`)
|
|
193
|
+
}
|
|
194
|
+
return this
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
// Simple table output
|
|
198
|
+
table(rows: Array<Record<string, string | number>>, options: { header?: boolean } = {}) {
|
|
199
|
+
this.stop()
|
|
200
|
+
if (quietMode || rows.length === 0) return this
|
|
201
|
+
|
|
202
|
+
const keys = Object.keys(rows[0])
|
|
203
|
+
const colWidths: Record<string, number> = {}
|
|
204
|
+
|
|
205
|
+
// Calculate column widths
|
|
206
|
+
for (const key of keys) {
|
|
207
|
+
colWidths[key] = key.length
|
|
208
|
+
for (const row of rows) {
|
|
209
|
+
const val = String(row[key] ?? '')
|
|
210
|
+
if (val.length > colWidths[key]) colWidths[key] = val.length
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Print header if requested
|
|
215
|
+
if (options.header !== false) {
|
|
216
|
+
const headerLine = keys.map((k) => k.padEnd(colWidths[k])).join(' ')
|
|
217
|
+
console.log(chalk.dim(headerLine))
|
|
218
|
+
console.log(chalk.dim('─'.repeat(headerLine.length)))
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Print rows
|
|
222
|
+
for (const row of rows) {
|
|
223
|
+
const line = keys.map((k) => String(row[k] ?? '').padEnd(colWidths[k])).join(' ')
|
|
224
|
+
console.log(line)
|
|
225
|
+
}
|
|
226
|
+
return this
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
// Boxed content
|
|
230
|
+
box(title: string, content: string) {
|
|
231
|
+
this.stop()
|
|
232
|
+
if (quietMode) return this
|
|
233
|
+
const lines = content.split('\n')
|
|
234
|
+
const maxLen = Math.max(title.length, ...lines.map((l) => l.length))
|
|
235
|
+
const border = '─'.repeat(maxLen + 2)
|
|
236
|
+
|
|
237
|
+
console.log(chalk.dim(`┌${border}┐`))
|
|
238
|
+
console.log(chalk.dim('│') + ` ${chalk.bold(title.padEnd(maxLen))} ` + chalk.dim('│'))
|
|
239
|
+
console.log(chalk.dim(`├${border}┤`))
|
|
240
|
+
for (const line of lines) {
|
|
241
|
+
console.log(chalk.dim('│') + ` ${line.padEnd(maxLen)} ` + chalk.dim('│'))
|
|
242
|
+
}
|
|
243
|
+
console.log(chalk.dim(`└${border}┘`))
|
|
136
244
|
return this
|
|
137
245
|
},
|
|
138
246
|
|
package/dist/bin/prjct.mjs
CHANGED
|
@@ -2065,6 +2065,7 @@ var init_error_messages = __esm({
|
|
|
2065
2065
|
var output_exports = {};
|
|
2066
2066
|
__export(output_exports, {
|
|
2067
2067
|
ERRORS: () => ERRORS,
|
|
2068
|
+
ICONS: () => ICONS,
|
|
2068
2069
|
createError: () => createError,
|
|
2069
2070
|
default: () => output_default,
|
|
2070
2071
|
getError: () => getError,
|
|
@@ -2078,7 +2079,7 @@ function setQuietMode(enabled) {
|
|
|
2078
2079
|
function isQuietMode() {
|
|
2079
2080
|
return quietMode;
|
|
2080
2081
|
}
|
|
2081
|
-
var _FRAMES, SPEED, interval, frame, quietMode, truncate, clear, out, output_default;
|
|
2082
|
+
var _FRAMES, SPEED, ICONS, interval, frame, quietMode, truncate, clear, out, output_default;
|
|
2082
2083
|
var init_output = __esm({
|
|
2083
2084
|
"core/utils/output.ts"() {
|
|
2084
2085
|
"use strict";
|
|
@@ -2087,6 +2088,18 @@ var init_output = __esm({
|
|
|
2087
2088
|
init_error_messages();
|
|
2088
2089
|
_FRAMES = branding_default.spinner.frames;
|
|
2089
2090
|
SPEED = branding_default.spinner.speed;
|
|
2091
|
+
ICONS = {
|
|
2092
|
+
success: chalk2.green("\u2713"),
|
|
2093
|
+
fail: chalk2.red("\u2717"),
|
|
2094
|
+
warn: chalk2.yellow("\u26A0"),
|
|
2095
|
+
info: chalk2.blue("\u2139"),
|
|
2096
|
+
debug: chalk2.dim("\u{1F527}"),
|
|
2097
|
+
bullet: chalk2.dim("\u2022"),
|
|
2098
|
+
arrow: chalk2.dim("\u2192"),
|
|
2099
|
+
check: chalk2.green("\u2713"),
|
|
2100
|
+
cross: chalk2.red("\u2717"),
|
|
2101
|
+
spinner: chalk2.cyan("\u25D0")
|
|
2102
|
+
};
|
|
2090
2103
|
interval = null;
|
|
2091
2104
|
frame = 0;
|
|
2092
2105
|
quietMode = false;
|
|
@@ -2127,14 +2140,14 @@ var init_output = __esm({
|
|
|
2127
2140
|
suffix = chalk2.dim(` [${parts.join(" | ")}]`);
|
|
2128
2141
|
}
|
|
2129
2142
|
}
|
|
2130
|
-
console.log(`${
|
|
2143
|
+
console.log(`${ICONS.success} ${truncate(msg, 50)}${suffix}`);
|
|
2131
2144
|
}
|
|
2132
2145
|
return this;
|
|
2133
2146
|
},
|
|
2134
2147
|
// Errors go to stderr even in quiet mode
|
|
2135
2148
|
fail(msg) {
|
|
2136
2149
|
this.stop();
|
|
2137
|
-
console.error(`${
|
|
2150
|
+
console.error(`${ICONS.fail} ${truncate(msg, 65)}`);
|
|
2138
2151
|
return this;
|
|
2139
2152
|
},
|
|
2140
2153
|
// Rich error with context and recovery hint
|
|
@@ -2142,7 +2155,7 @@ var init_output = __esm({
|
|
|
2142
2155
|
this.stop();
|
|
2143
2156
|
const err = typeof error === "string" ? getError(error) : error;
|
|
2144
2157
|
console.error();
|
|
2145
|
-
console.error(`${
|
|
2158
|
+
console.error(`${ICONS.fail} ${err.message}`);
|
|
2146
2159
|
if (err.file) {
|
|
2147
2160
|
console.error(chalk2.dim(` File: ${err.file}`));
|
|
2148
2161
|
}
|
|
@@ -2157,7 +2170,77 @@ var init_output = __esm({
|
|
|
2157
2170
|
},
|
|
2158
2171
|
warn(msg) {
|
|
2159
2172
|
this.stop();
|
|
2160
|
-
if (!quietMode) console.log(`${
|
|
2173
|
+
if (!quietMode) console.log(`${ICONS.warn} ${truncate(msg, 65)}`);
|
|
2174
|
+
return this;
|
|
2175
|
+
},
|
|
2176
|
+
// Informational message
|
|
2177
|
+
info(msg) {
|
|
2178
|
+
this.stop();
|
|
2179
|
+
if (!quietMode) console.log(`${ICONS.info} ${msg}`);
|
|
2180
|
+
return this;
|
|
2181
|
+
},
|
|
2182
|
+
// Debug message (only if DEBUG=1 or DEBUG=true)
|
|
2183
|
+
debug(msg) {
|
|
2184
|
+
this.stop();
|
|
2185
|
+
const debugEnabled = process.env.DEBUG === "1" || process.env.DEBUG === "true";
|
|
2186
|
+
if (!quietMode && debugEnabled) {
|
|
2187
|
+
console.log(`${ICONS.debug} ${chalk2.dim(msg)}`);
|
|
2188
|
+
}
|
|
2189
|
+
return this;
|
|
2190
|
+
},
|
|
2191
|
+
// Alias for done - explicit success indicator
|
|
2192
|
+
success(msg, metrics) {
|
|
2193
|
+
return this.done(msg, metrics);
|
|
2194
|
+
},
|
|
2195
|
+
// Bulleted list
|
|
2196
|
+
list(items, options = {}) {
|
|
2197
|
+
this.stop();
|
|
2198
|
+
if (quietMode) return this;
|
|
2199
|
+
const bullet = options.bullet || ICONS.bullet;
|
|
2200
|
+
const indent = " ".repeat(options.indent || 0);
|
|
2201
|
+
for (const item of items) {
|
|
2202
|
+
console.log(`${indent}${bullet} ${item}`);
|
|
2203
|
+
}
|
|
2204
|
+
return this;
|
|
2205
|
+
},
|
|
2206
|
+
// Simple table output
|
|
2207
|
+
table(rows, options = {}) {
|
|
2208
|
+
this.stop();
|
|
2209
|
+
if (quietMode || rows.length === 0) return this;
|
|
2210
|
+
const keys = Object.keys(rows[0]);
|
|
2211
|
+
const colWidths = {};
|
|
2212
|
+
for (const key of keys) {
|
|
2213
|
+
colWidths[key] = key.length;
|
|
2214
|
+
for (const row of rows) {
|
|
2215
|
+
const val = String(row[key] ?? "");
|
|
2216
|
+
if (val.length > colWidths[key]) colWidths[key] = val.length;
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
if (options.header !== false) {
|
|
2220
|
+
const headerLine = keys.map((k) => k.padEnd(colWidths[k])).join(" ");
|
|
2221
|
+
console.log(chalk2.dim(headerLine));
|
|
2222
|
+
console.log(chalk2.dim("\u2500".repeat(headerLine.length)));
|
|
2223
|
+
}
|
|
2224
|
+
for (const row of rows) {
|
|
2225
|
+
const line = keys.map((k) => String(row[k] ?? "").padEnd(colWidths[k])).join(" ");
|
|
2226
|
+
console.log(line);
|
|
2227
|
+
}
|
|
2228
|
+
return this;
|
|
2229
|
+
},
|
|
2230
|
+
// Boxed content
|
|
2231
|
+
box(title, content) {
|
|
2232
|
+
this.stop();
|
|
2233
|
+
if (quietMode) return this;
|
|
2234
|
+
const lines = content.split("\n");
|
|
2235
|
+
const maxLen = Math.max(title.length, ...lines.map((l) => l.length));
|
|
2236
|
+
const border = "\u2500".repeat(maxLen + 2);
|
|
2237
|
+
console.log(chalk2.dim(`\u250C${border}\u2510`));
|
|
2238
|
+
console.log(chalk2.dim("\u2502") + ` ${chalk2.bold(title.padEnd(maxLen))} ` + chalk2.dim("\u2502"));
|
|
2239
|
+
console.log(chalk2.dim(`\u251C${border}\u2524`));
|
|
2240
|
+
for (const line of lines) {
|
|
2241
|
+
console.log(chalk2.dim("\u2502") + ` ${line.padEnd(maxLen)} ` + chalk2.dim("\u2502"));
|
|
2242
|
+
}
|
|
2243
|
+
console.log(chalk2.dim(`\u2514${border}\u2518`));
|
|
2161
2244
|
return this;
|
|
2162
2245
|
},
|
|
2163
2246
|
stop() {
|
|
@@ -24220,7 +24303,7 @@ var require_package = __commonJS({
|
|
|
24220
24303
|
"package.json"(exports, module) {
|
|
24221
24304
|
module.exports = {
|
|
24222
24305
|
name: "prjct-cli",
|
|
24223
|
-
version: "0.
|
|
24306
|
+
version: "0.50.0",
|
|
24224
24307
|
description: "Context layer for AI agents. Project context for Claude Code, Gemini CLI, and more.",
|
|
24225
24308
|
main: "core/index.ts",
|
|
24226
24309
|
bin: {
|