@rol1n/screenshot 0.0.0-stage → 0.1.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.
Files changed (3) hide show
  1. package/README.md +13 -2
  2. package/index.ts +126 -0
  3. package/package.json +37 -4
package/README.md CHANGED
@@ -1,3 +1,14 @@
1
- # Temporary Holding Version
1
+ # screenshot
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Insert the file path of the most recently modified Windows/WSL system screenshot into Pi's editor via `/screenshot`.
4
+
5
+ Searches standard and localized `Pictures/Screenshots` and OneDrive screenshot directories under `USERPROFILE` on Windows or `/mnt/c/Users` on WSL.
6
+
7
+
8
+ ## Install
9
+
10
+ ```sh
11
+ pi install npm:@rol1n/screenshot
12
+ ```
13
+
14
+ Available as a standalone package (not enabled in `@rol1n/pi-kit` by default).
package/index.ts ADDED
@@ -0,0 +1,126 @@
1
+ /**
2
+ * screenshot — Insert the latest Windows/WSL system screenshot path into Pi's editor.
3
+ */
4
+
5
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
6
+ import { extname, join } from "node:path";
7
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
8
+
9
+ const SCREENSHOT_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"]);
10
+ const SKIP_USER_DIRS = /^(Public|Default|Default User|All Users|desktop\.ini)$/i;
11
+
12
+ function isExpectedFileSystemError(error: unknown): boolean {
13
+ return error instanceof Error && "code" in error &&
14
+ ["ENOENT", "ENOTDIR", "EACCES", "EPERM"].includes(String(error.code));
15
+ }
16
+
17
+ function isWindows(): boolean {
18
+ return process.platform === "win32";
19
+ }
20
+
21
+ function isWSL(): boolean {
22
+ if (process.platform !== "linux") return false;
23
+ if (process.env.WSL_DISTRO_NAME || process.env.WSLENV || existsSync("/mnt/c/Users")) return true;
24
+ try {
25
+ return /microsoft|wsl/i.test(readFileSync("/proc/version", "utf-8"));
26
+ } catch (error) {
27
+ if (isExpectedFileSystemError(error)) return false;
28
+ throw error;
29
+ }
30
+ }
31
+
32
+ export function supportsScreenshots(): boolean {
33
+ return isWindows() || isWSL();
34
+ }
35
+
36
+ function findScreenshotDirs(): string[] {
37
+ const dirs = new Set<string>();
38
+ const addIfDirectory = (path: string) => {
39
+ try {
40
+ if (existsSync(path) && statSync(path).isDirectory()) dirs.add(path);
41
+ } catch (error) {
42
+ if (!isExpectedFileSystemError(error)) throw error;
43
+ }
44
+ };
45
+
46
+ if (isWindows()) {
47
+ const profile = process.env.USERPROFILE || process.env.HOME;
48
+ if (profile) {
49
+ addIfDirectory(join(profile, "Pictures", "Screenshots"));
50
+ addIfDirectory(join(profile, "Pictures", "屏幕截图"));
51
+ addIfDirectory(join(profile, "OneDrive", "Pictures", "Screenshots"));
52
+ addIfDirectory(join(profile, "OneDrive", "图片", "屏幕截图"));
53
+ addIfDirectory(join(profile, "OneDrive", "Pictures", "屏幕截图"));
54
+ }
55
+ }
56
+
57
+ if (isWSL()) {
58
+ const usersRoot = "/mnt/c/Users";
59
+ try {
60
+ for (const entry of readdirSync(usersRoot, { withFileTypes: true })) {
61
+ if (!entry.isDirectory() || SKIP_USER_DIRS.test(entry.name)) continue;
62
+ const profile = join(usersRoot, entry.name);
63
+ addIfDirectory(join(profile, "Pictures", "Screenshots"));
64
+ addIfDirectory(join(profile, "Pictures", "屏幕截图"));
65
+ addIfDirectory(join(profile, "OneDrive", "Pictures", "Screenshots"));
66
+ addIfDirectory(join(profile, "OneDrive", "图片", "屏幕截图"));
67
+ }
68
+ } catch (error) {
69
+ if (!isExpectedFileSystemError(error)) throw error;
70
+ }
71
+ }
72
+
73
+ return [...dirs];
74
+ }
75
+
76
+ export function findLatestScreenshot(): string | null {
77
+ let latestPath: string | null = null;
78
+ let latestMtime = -1;
79
+
80
+ for (const dir of findScreenshotDirs()) {
81
+ let files: string[];
82
+ try {
83
+ files = readdirSync(dir);
84
+ } catch (error) {
85
+ if (isExpectedFileSystemError(error)) continue;
86
+ throw error;
87
+ }
88
+
89
+ for (const file of files) {
90
+ if (!SCREENSHOT_EXTENSIONS.has(extname(file).toLowerCase())) continue;
91
+ const path = join(dir, file);
92
+ try {
93
+ const stat = statSync(path);
94
+ if (stat.isFile() && stat.mtimeMs > latestMtime) {
95
+ latestPath = path;
96
+ latestMtime = stat.mtimeMs;
97
+ }
98
+ } catch (error) {
99
+ if (!isExpectedFileSystemError(error)) throw error;
100
+ }
101
+ }
102
+ }
103
+
104
+ return latestPath;
105
+ }
106
+
107
+ export default function (pi: ExtensionAPI) {
108
+ pi.registerCommand("screenshot", {
109
+ description: "Insert the latest Windows/WSL system screenshot path into the editor",
110
+ handler: async (_args, ctx: ExtensionContext) => {
111
+ if (!supportsScreenshots()) {
112
+ ctx.ui.notify("Current environment is not Windows or WSL; cannot locate Windows screenshots.", "warning");
113
+ return;
114
+ }
115
+
116
+ const path = findLatestScreenshot();
117
+ if (!path) {
118
+ ctx.ui.notify("No Windows screenshots found.", "warning");
119
+ return;
120
+ }
121
+
122
+ ctx.ui.pasteToEditor(`${path} `);
123
+ ctx.ui.notify(`Referenced screenshot: ${path.split(/[\\/]/).pop()}`, "info");
124
+ },
125
+ });
126
+ }
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "@rol1n/screenshot",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "description": "screenshot extension from pi-kit",
6
+ "keywords": [
7
+ "pi-package"
8
+ ],
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/RolinShmily/pi-kit.git",
12
+ "directory": "screenshot"
13
+ },
14
+ "homepage": "https://github.com/RolinShmily/pi-kit#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/RolinShmily/pi-kit/issues"
17
+ },
18
+ "engines": {
19
+ "node": ">=22.19.0"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "peerDependencies": {
25
+ "@earendil-works/pi-ai": "*",
26
+ "@earendil-works/pi-agent-core": "*",
27
+ "@earendil-works/pi-coding-agent": "*",
28
+ "@earendil-works/pi-tui": "*",
29
+ "typebox": "*"
30
+ },
31
+ "pi": {
32
+ "extensions": [
33
+ "./index.ts"
34
+ ],
35
+ "skills": [],
36
+ "prompts": [],
37
+ "themes": []
38
+ }
39
+ }