podwatch 1.0.2

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 (51) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +92 -0
  3. package/bin/podwatch.js +10 -0
  4. package/dist/classifier.d.ts +22 -0
  5. package/dist/classifier.d.ts.map +1 -0
  6. package/dist/classifier.js +157 -0
  7. package/dist/classifier.js.map +1 -0
  8. package/dist/hooks/cost.d.ts +26 -0
  9. package/dist/hooks/cost.d.ts.map +1 -0
  10. package/dist/hooks/cost.js +107 -0
  11. package/dist/hooks/cost.js.map +1 -0
  12. package/dist/hooks/lifecycle.d.ts +16 -0
  13. package/dist/hooks/lifecycle.d.ts.map +1 -0
  14. package/dist/hooks/lifecycle.js +273 -0
  15. package/dist/hooks/lifecycle.js.map +1 -0
  16. package/dist/hooks/security.d.ts +19 -0
  17. package/dist/hooks/security.d.ts.map +1 -0
  18. package/dist/hooks/security.js +128 -0
  19. package/dist/hooks/security.js.map +1 -0
  20. package/dist/hooks/sessions.d.ts +10 -0
  21. package/dist/hooks/sessions.d.ts.map +1 -0
  22. package/dist/hooks/sessions.js +53 -0
  23. package/dist/hooks/sessions.js.map +1 -0
  24. package/dist/index.d.ts +32 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/index.js +120 -0
  27. package/dist/index.js.map +1 -0
  28. package/dist/redact.d.ts +35 -0
  29. package/dist/redact.d.ts.map +1 -0
  30. package/dist/redact.js +372 -0
  31. package/dist/redact.js.map +1 -0
  32. package/dist/scanner.d.ts +27 -0
  33. package/dist/scanner.d.ts.map +1 -0
  34. package/dist/scanner.js +117 -0
  35. package/dist/scanner.js.map +1 -0
  36. package/dist/transmitter.d.ts +58 -0
  37. package/dist/transmitter.d.ts.map +1 -0
  38. package/dist/transmitter.js +654 -0
  39. package/dist/transmitter.js.map +1 -0
  40. package/dist/types.d.ts +116 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +9 -0
  43. package/dist/types.js.map +1 -0
  44. package/dist/updater.d.ts +168 -0
  45. package/dist/updater.d.ts.map +1 -0
  46. package/dist/updater.js +579 -0
  47. package/dist/updater.js.map +1 -0
  48. package/lib/installer.js +599 -0
  49. package/openclaw.plugin.json +59 -0
  50. package/package.json +56 -0
  51. package/skills/podwatch/SKILL.md +112 -0
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ /**
3
+ * Skill/plugin scanner — scans installed skills and plugins.
4
+ *
5
+ * Scans:
6
+ * - ~/.openclaw/skills/ (managed skills)
7
+ * - <workspace>/skills/ (workspace skills)
8
+ * - ~/.openclaw/extensions/ (installed plugins)
9
+ *
10
+ * Reports: name, version, source, permissions, risk indicators.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.scanSkillsAndPlugins = scanSkillsAndPlugins;
14
+ const promises_1 = require("node:fs/promises");
15
+ const node_path_1 = require("node:path");
16
+ const node_os_1 = require("node:os");
17
+ // ---------------------------------------------------------------------------
18
+ // Scanner
19
+ // ---------------------------------------------------------------------------
20
+ async function scanSkillsAndPlugins(workspaceDir) {
21
+ const home = (0, node_os_1.homedir)();
22
+ const skills = [];
23
+ const plugins = [];
24
+ // Scan managed skills
25
+ await scanDirectory((0, node_path_1.resolve)(home, ".openclaw", "skills"), "skill", "managed", skills);
26
+ // Scan workspace skills
27
+ if (workspaceDir) {
28
+ await scanDirectory((0, node_path_1.resolve)(workspaceDir, "skills"), "skill", "workspace", skills);
29
+ }
30
+ // Scan installed plugins/extensions
31
+ await scanDirectory((0, node_path_1.resolve)(home, ".openclaw", "extensions"), "plugin", "installed", plugins);
32
+ return {
33
+ skills,
34
+ plugins,
35
+ scannedAt: Date.now(),
36
+ };
37
+ }
38
+ // ---------------------------------------------------------------------------
39
+ // Helpers
40
+ // ---------------------------------------------------------------------------
41
+ async function scanDirectory(dir, type, source, results) {
42
+ try {
43
+ const entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
44
+ for (const entry of entries) {
45
+ if (!entry.isDirectory())
46
+ continue;
47
+ const itemDir = (0, node_path_1.join)(dir, entry.name);
48
+ const item = {
49
+ name: entry.name,
50
+ type,
51
+ source,
52
+ };
53
+ // Try to read metadata
54
+ if (type === "skill") {
55
+ await readSkillMeta(itemDir, item);
56
+ }
57
+ else {
58
+ await readPluginMeta(itemDir, item);
59
+ }
60
+ results.push(item);
61
+ }
62
+ }
63
+ catch {
64
+ // Directory doesn't exist — that's fine
65
+ }
66
+ }
67
+ async function readSkillMeta(dir, item) {
68
+ try {
69
+ const skillMd = await (0, promises_1.readFile)((0, node_path_1.join)(dir, "SKILL.md"), "utf-8");
70
+ // Parse YAML frontmatter
71
+ const match = skillMd.match(/^---\n([\s\S]*?)\n---/);
72
+ if (match) {
73
+ const frontmatter = match[1];
74
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
75
+ const descMatch = frontmatter.match(/^description:\s*"?(.+?)"?$/m);
76
+ const versionMatch = frontmatter.match(/^version:\s*(.+)$/m);
77
+ if (nameMatch)
78
+ item.name = nameMatch[1].trim();
79
+ if (descMatch)
80
+ item.description = descMatch[1].trim();
81
+ if (versionMatch)
82
+ item.version = versionMatch[1].trim();
83
+ }
84
+ }
85
+ catch {
86
+ // No SKILL.md — skip metadata
87
+ }
88
+ }
89
+ async function readPluginMeta(dir, item) {
90
+ try {
91
+ const manifest = await (0, promises_1.readFile)((0, node_path_1.join)(dir, "openclaw.plugin.json"), "utf-8");
92
+ const parsed = JSON.parse(manifest);
93
+ if (parsed.name)
94
+ item.name = parsed.name;
95
+ if (parsed.version)
96
+ item.version = parsed.version;
97
+ if (parsed.description)
98
+ item.description = parsed.description;
99
+ }
100
+ catch {
101
+ // Try package.json fallback
102
+ try {
103
+ const pkg = await (0, promises_1.readFile)((0, node_path_1.join)(dir, "package.json"), "utf-8");
104
+ const parsed = JSON.parse(pkg);
105
+ if (parsed.name)
106
+ item.name = parsed.name;
107
+ if (parsed.version)
108
+ item.version = parsed.version;
109
+ if (parsed.description)
110
+ item.description = parsed.description;
111
+ }
112
+ catch {
113
+ // No metadata available
114
+ }
115
+ }
116
+ }
117
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Batched HTTP transmitter — queues events and flushes to Podwatch cloud.
3
+ *
4
+ * Features:
5
+ * - Configurable batch size and flush interval
6
+ * - Exponential backoff on failure
7
+ * - Buffer overflow protection (drops SAFE events first)
8
+ * - Graceful shutdown (flush on gateway_stop)
9
+ * - Credential access tracking (for exfiltration detection)
10
+ * - Known tool tracking (for first-time tool alerts)
11
+ * - Cached budget state (synced every 60s from dashboard)
12
+ * - Local audit log for dropped events
13
+ * - 402 trial-expired handling
14
+ */
15
+ import type { TransmitterConfig, PodwatchEvent } from "./types.js";
16
+ interface CredentialAccess {
17
+ toolName: string;
18
+ path: string;
19
+ ts: number;
20
+ }
21
+ interface CachedBudget {
22
+ limit: number;
23
+ currentSpend: number;
24
+ lastSyncTs: number;
25
+ }
26
+ export declare const transmitter: {
27
+ start(cfg: TransmitterConfig): void;
28
+ enqueue(event: PodwatchEvent): void;
29
+ flush(): Promise<void>;
30
+ stop(): void;
31
+ /** Flush remaining events and stop. For graceful shutdown. */
32
+ shutdown(): Promise<void>;
33
+ /** Mark that a tool accessed credentials. */
34
+ markCredentialAccess(toolName: string, params: Record<string, unknown>): void;
35
+ /** Check if there was a credential access within the last `windowSec` seconds. */
36
+ hasRecentCredentialAccess(windowSec: number): boolean;
37
+ /** Get the most recent credential access details (for exfiltration alerts). */
38
+ getRecentCredentialAccess(windowSec: number): CredentialAccess | null;
39
+ _pruneCredentialAccesses(): void;
40
+ /** Check if a tool has been seen before. */
41
+ isKnownTool(toolName: string): boolean;
42
+ /** Record a tool as seen. Clears the set when it exceeds KNOWN_TOOLS_MAX_SIZE. */
43
+ recordToolSeen(toolName: string): void;
44
+ /** Get agent uptime in hours since plugin activated. */
45
+ getAgentUptimeHours(): number;
46
+ /** Get cached budget state (synced from dashboard every 60s). */
47
+ getCachedBudget(): CachedBudget | null;
48
+ /** Force a budget sync now. */
49
+ forceBudgetSync(): Promise<void>;
50
+ /** Current buffer size (for testing/diagnostics). */
51
+ readonly bufferedCount: number;
52
+ /** Number of known tools (for testing/diagnostics). */
53
+ readonly knownToolCount: number;
54
+ /** Whether trial has expired (for testing). */
55
+ readonly isTrialExpired: boolean;
56
+ };
57
+ export {};
58
+ //# sourceMappingURL=transmitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transmitter.d.ts","sourceRoot":"","sources":["../src/transmitter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6BnE,UAAU,gBAAgB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAWD,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AA8ZD,eAAO,MAAM,WAAW;eACX,iBAAiB,GAAG,IAAI;mBA4BpB,aAAa,GAAG,IAAI;aA6CpB,OAAO,CAAC,IAAI,CAAC;YAIpB,IAAI;IAWZ,8DAA8D;gBAC5C,OAAO,CAAC,IAAI,CAAC;IAW/B,6CAA6C;mCACd,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAiB7E,kFAAkF;yCAC7C,MAAM,GAAG,OAAO;IAMrD,+EAA+E;yCAC1C,MAAM,GAAG,gBAAgB,GAAG,IAAI;gCAOzC,IAAI;IAWhC,4CAA4C;0BACtB,MAAM,GAAG,OAAO;IAItC,kFAAkF;6BACzD,MAAM,GAAG,IAAI;IAWtC,wDAAwD;2BACjC,MAAM;IAS7B,iEAAiE;uBAC9C,YAAY,GAAG,IAAI;IAItC,+BAA+B;uBACN,OAAO,CAAC,IAAI,CAAC;IAQtC,qDAAqD;4BAChC,MAAM;IAI3B,uDAAuD;6BACjC,MAAM;IAI5B,+CAA+C;6BACzB,OAAO;CAG9B,CAAC"}