gsd-pi 2.28.0-dev.4009980 → 2.28.0-dev.b23c118
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.
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
5
5
|
import { writeFileSync, mkdirSync } from "node:fs";
|
|
6
6
|
import { join, basename } from "node:path";
|
|
7
|
+
import { exec } from "node:child_process";
|
|
7
8
|
import {
|
|
8
9
|
getLedger, getProjectTotals, aggregateByPhase, aggregateBySlice,
|
|
9
10
|
aggregateByModel, formatCost, formatTokenCount, loadLedgerFromDisk,
|
|
@@ -12,6 +13,28 @@ import type { UnitMetrics } from "./metrics.js";
|
|
|
12
13
|
import { gsdRoot } from "./paths.js";
|
|
13
14
|
import { formatDuration, fileLink } from "../shared/mod.js";
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Open a file in the user's default browser.
|
|
18
|
+
* Uses platform-specific commands: `open` (macOS), `xdg-open` (Linux), `start` (Windows).
|
|
19
|
+
* Non-blocking, non-fatal — failures are silently ignored.
|
|
20
|
+
*/
|
|
21
|
+
export function openInBrowser(filePath: string): void {
|
|
22
|
+
const cmd =
|
|
23
|
+
process.platform === "darwin" ? "open" :
|
|
24
|
+
process.platform === "win32" ? "start" :
|
|
25
|
+
"xdg-open";
|
|
26
|
+
|
|
27
|
+
// On Windows, `start` needs an empty title argument when the path has spaces
|
|
28
|
+
const args = process.platform === "win32"
|
|
29
|
+
? `"" "${filePath}"`
|
|
30
|
+
: `"${filePath}"`;
|
|
31
|
+
|
|
32
|
+
exec(`${cmd} ${args}`, (err) => {
|
|
33
|
+
// Non-fatal — if the browser can't be opened, the file path is still shown
|
|
34
|
+
if (err) void err;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
15
38
|
/**
|
|
16
39
|
* Write an export file directly, without requiring an ExtensionCommandContext.
|
|
17
40
|
* Used by the visualizer overlay export tab.
|
|
@@ -167,10 +190,12 @@ export async function handleExport(args: string, ctx: ExtensionCommandContext, b
|
|
|
167
190
|
paths.push(bn(outPath));
|
|
168
191
|
}
|
|
169
192
|
|
|
193
|
+
const indexPath = join(gsdRoot(basePath), "reports", "index.html");
|
|
170
194
|
ctx.ui.notify(
|
|
171
|
-
`Generated ${paths.length} report snapshot${paths.length !== 1 ? "s" : ""}:\n${paths.map(p => ` ${p}`).join("\n")}\
|
|
195
|
+
`Generated ${paths.length} report snapshot${paths.length !== 1 ? "s" : ""}:\n${paths.map(p => ` ${p}`).join("\n")}\nOpening reports index in browser...`,
|
|
172
196
|
"success",
|
|
173
197
|
);
|
|
198
|
+
openInBrowser(indexPath);
|
|
174
199
|
} else {
|
|
175
200
|
// Single report for the active milestone (existing behavior)
|
|
176
201
|
const doneSlices = data.milestones.reduce((s, m) => s + m.slices.filter(sl => sl.done).length, 0);
|
|
@@ -194,9 +219,10 @@ export async function handleExport(args: string, ctx: ExtensionCommandContext, b
|
|
|
194
219
|
phase: data.phase,
|
|
195
220
|
});
|
|
196
221
|
ctx.ui.notify(
|
|
197
|
-
`HTML report saved: .gsd/reports/${bn(outPath)}\
|
|
222
|
+
`HTML report saved: .gsd/reports/${bn(outPath)}\nOpening in browser...`,
|
|
198
223
|
"success",
|
|
199
224
|
);
|
|
225
|
+
openInBrowser(outPath);
|
|
200
226
|
}
|
|
201
227
|
} catch (err) {
|
|
202
228
|
ctx.ui.notify(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gsd-pi",
|
|
3
|
-
"version": "2.28.0-dev.
|
|
3
|
+
"version": "2.28.0-dev.b23c118",
|
|
4
4
|
"description": "GSD — Get Shit Done coding agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"configDir": ".gsd"
|
|
36
36
|
},
|
|
37
37
|
"engines": {
|
|
38
|
-
"node": ">=
|
|
38
|
+
"node": ">=22.0.0"
|
|
39
39
|
},
|
|
40
40
|
"packageManager": "npm@10.9.3",
|
|
41
41
|
"scripts": {
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"zod-to-json-schema": "^3.24.6"
|
|
118
118
|
},
|
|
119
119
|
"devDependencies": {
|
|
120
|
-
"@types/node": "^
|
|
120
|
+
"@types/node": "^24.12.0",
|
|
121
121
|
"@types/picomatch": "^4.0.2",
|
|
122
122
|
"c8": "^11.0.0",
|
|
123
123
|
"jiti": "^2.6.1",
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
5
5
|
import { writeFileSync, mkdirSync } from "node:fs";
|
|
6
6
|
import { join, basename } from "node:path";
|
|
7
|
+
import { exec } from "node:child_process";
|
|
7
8
|
import {
|
|
8
9
|
getLedger, getProjectTotals, aggregateByPhase, aggregateBySlice,
|
|
9
10
|
aggregateByModel, formatCost, formatTokenCount, loadLedgerFromDisk,
|
|
@@ -12,6 +13,28 @@ import type { UnitMetrics } from "./metrics.js";
|
|
|
12
13
|
import { gsdRoot } from "./paths.js";
|
|
13
14
|
import { formatDuration, fileLink } from "../shared/mod.js";
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Open a file in the user's default browser.
|
|
18
|
+
* Uses platform-specific commands: `open` (macOS), `xdg-open` (Linux), `start` (Windows).
|
|
19
|
+
* Non-blocking, non-fatal — failures are silently ignored.
|
|
20
|
+
*/
|
|
21
|
+
export function openInBrowser(filePath: string): void {
|
|
22
|
+
const cmd =
|
|
23
|
+
process.platform === "darwin" ? "open" :
|
|
24
|
+
process.platform === "win32" ? "start" :
|
|
25
|
+
"xdg-open";
|
|
26
|
+
|
|
27
|
+
// On Windows, `start` needs an empty title argument when the path has spaces
|
|
28
|
+
const args = process.platform === "win32"
|
|
29
|
+
? `"" "${filePath}"`
|
|
30
|
+
: `"${filePath}"`;
|
|
31
|
+
|
|
32
|
+
exec(`${cmd} ${args}`, (err) => {
|
|
33
|
+
// Non-fatal — if the browser can't be opened, the file path is still shown
|
|
34
|
+
if (err) void err;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
15
38
|
/**
|
|
16
39
|
* Write an export file directly, without requiring an ExtensionCommandContext.
|
|
17
40
|
* Used by the visualizer overlay export tab.
|
|
@@ -167,10 +190,12 @@ export async function handleExport(args: string, ctx: ExtensionCommandContext, b
|
|
|
167
190
|
paths.push(bn(outPath));
|
|
168
191
|
}
|
|
169
192
|
|
|
193
|
+
const indexPath = join(gsdRoot(basePath), "reports", "index.html");
|
|
170
194
|
ctx.ui.notify(
|
|
171
|
-
`Generated ${paths.length} report snapshot${paths.length !== 1 ? "s" : ""}:\n${paths.map(p => ` ${p}`).join("\n")}\
|
|
195
|
+
`Generated ${paths.length} report snapshot${paths.length !== 1 ? "s" : ""}:\n${paths.map(p => ` ${p}`).join("\n")}\nOpening reports index in browser...`,
|
|
172
196
|
"success",
|
|
173
197
|
);
|
|
198
|
+
openInBrowser(indexPath);
|
|
174
199
|
} else {
|
|
175
200
|
// Single report for the active milestone (existing behavior)
|
|
176
201
|
const doneSlices = data.milestones.reduce((s, m) => s + m.slices.filter(sl => sl.done).length, 0);
|
|
@@ -194,9 +219,10 @@ export async function handleExport(args: string, ctx: ExtensionCommandContext, b
|
|
|
194
219
|
phase: data.phase,
|
|
195
220
|
});
|
|
196
221
|
ctx.ui.notify(
|
|
197
|
-
`HTML report saved: .gsd/reports/${bn(outPath)}\
|
|
222
|
+
`HTML report saved: .gsd/reports/${bn(outPath)}\nOpening in browser...`,
|
|
198
223
|
"success",
|
|
199
224
|
);
|
|
225
|
+
openInBrowser(outPath);
|
|
200
226
|
}
|
|
201
227
|
} catch (err) {
|
|
202
228
|
ctx.ui.notify(
|