codepiper 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.
Files changed (149) hide show
  1. package/.env.example +28 -0
  2. package/CHANGELOG.md +10 -0
  3. package/LEGAL_NOTICE.md +39 -0
  4. package/LICENSE +21 -0
  5. package/README.md +524 -0
  6. package/package.json +90 -0
  7. package/packages/cli/package.json +13 -0
  8. package/packages/cli/src/commands/analytics.ts +157 -0
  9. package/packages/cli/src/commands/attach.ts +299 -0
  10. package/packages/cli/src/commands/audit.ts +50 -0
  11. package/packages/cli/src/commands/auth.ts +261 -0
  12. package/packages/cli/src/commands/daemon.ts +162 -0
  13. package/packages/cli/src/commands/doctor.ts +303 -0
  14. package/packages/cli/src/commands/env-set.ts +162 -0
  15. package/packages/cli/src/commands/hook-forward.ts +268 -0
  16. package/packages/cli/src/commands/keys.ts +77 -0
  17. package/packages/cli/src/commands/kill.ts +19 -0
  18. package/packages/cli/src/commands/logs.ts +419 -0
  19. package/packages/cli/src/commands/model.ts +172 -0
  20. package/packages/cli/src/commands/policy-set.ts +185 -0
  21. package/packages/cli/src/commands/policy.ts +227 -0
  22. package/packages/cli/src/commands/providers.ts +114 -0
  23. package/packages/cli/src/commands/resize.ts +34 -0
  24. package/packages/cli/src/commands/send.ts +184 -0
  25. package/packages/cli/src/commands/sessions.ts +202 -0
  26. package/packages/cli/src/commands/slash.ts +92 -0
  27. package/packages/cli/src/commands/start.ts +243 -0
  28. package/packages/cli/src/commands/stop.ts +19 -0
  29. package/packages/cli/src/commands/tail.ts +137 -0
  30. package/packages/cli/src/commands/workflow.ts +786 -0
  31. package/packages/cli/src/commands/workspace.ts +127 -0
  32. package/packages/cli/src/lib/api.ts +78 -0
  33. package/packages/cli/src/lib/args.ts +72 -0
  34. package/packages/cli/src/lib/format.ts +93 -0
  35. package/packages/cli/src/main.ts +563 -0
  36. package/packages/core/package.json +7 -0
  37. package/packages/core/src/config.ts +30 -0
  38. package/packages/core/src/errors.ts +38 -0
  39. package/packages/core/src/eventBus.ts +56 -0
  40. package/packages/core/src/eventBusAdapter.ts +143 -0
  41. package/packages/core/src/index.ts +10 -0
  42. package/packages/core/src/sqliteEventBus.ts +336 -0
  43. package/packages/core/src/types.ts +63 -0
  44. package/packages/daemon/package.json +11 -0
  45. package/packages/daemon/src/api/analyticsRoutes.ts +343 -0
  46. package/packages/daemon/src/api/authRoutes.ts +344 -0
  47. package/packages/daemon/src/api/bodyLimit.ts +133 -0
  48. package/packages/daemon/src/api/envSetRoutes.ts +170 -0
  49. package/packages/daemon/src/api/gitRoutes.ts +409 -0
  50. package/packages/daemon/src/api/hooks.ts +588 -0
  51. package/packages/daemon/src/api/inputPolicy.ts +249 -0
  52. package/packages/daemon/src/api/notificationRoutes.ts +532 -0
  53. package/packages/daemon/src/api/policyRoutes.ts +234 -0
  54. package/packages/daemon/src/api/policySetRoutes.ts +445 -0
  55. package/packages/daemon/src/api/routeUtils.ts +28 -0
  56. package/packages/daemon/src/api/routes.ts +1004 -0
  57. package/packages/daemon/src/api/server.ts +1388 -0
  58. package/packages/daemon/src/api/settingsRoutes.ts +367 -0
  59. package/packages/daemon/src/api/sqliteErrors.ts +47 -0
  60. package/packages/daemon/src/api/stt.ts +143 -0
  61. package/packages/daemon/src/api/terminalRoutes.ts +200 -0
  62. package/packages/daemon/src/api/validation.ts +287 -0
  63. package/packages/daemon/src/api/validationRoutes.ts +174 -0
  64. package/packages/daemon/src/api/workflowRoutes.ts +567 -0
  65. package/packages/daemon/src/api/workspaceRoutes.ts +151 -0
  66. package/packages/daemon/src/api/ws.ts +1588 -0
  67. package/packages/daemon/src/auth/apiRateLimiter.ts +73 -0
  68. package/packages/daemon/src/auth/authMiddleware.ts +305 -0
  69. package/packages/daemon/src/auth/authService.ts +496 -0
  70. package/packages/daemon/src/auth/rateLimiter.ts +137 -0
  71. package/packages/daemon/src/config/pricing.ts +79 -0
  72. package/packages/daemon/src/crypto/encryption.ts +196 -0
  73. package/packages/daemon/src/db/db.ts +2745 -0
  74. package/packages/daemon/src/db/index.ts +16 -0
  75. package/packages/daemon/src/db/migrations.ts +182 -0
  76. package/packages/daemon/src/db/policyDb.ts +349 -0
  77. package/packages/daemon/src/db/schema.sql +408 -0
  78. package/packages/daemon/src/db/workflowDb.ts +464 -0
  79. package/packages/daemon/src/git/gitUtils.ts +544 -0
  80. package/packages/daemon/src/index.ts +6 -0
  81. package/packages/daemon/src/main.ts +525 -0
  82. package/packages/daemon/src/notifications/pushNotifier.ts +369 -0
  83. package/packages/daemon/src/providers/codexAppServerScaffold.ts +49 -0
  84. package/packages/daemon/src/providers/registry.ts +111 -0
  85. package/packages/daemon/src/providers/types.ts +82 -0
  86. package/packages/daemon/src/sessions/auditLogger.ts +103 -0
  87. package/packages/daemon/src/sessions/policyEngine.ts +165 -0
  88. package/packages/daemon/src/sessions/policyMatcher.ts +114 -0
  89. package/packages/daemon/src/sessions/policyTypes.ts +94 -0
  90. package/packages/daemon/src/sessions/ptyProcess.ts +141 -0
  91. package/packages/daemon/src/sessions/sessionManager.ts +1770 -0
  92. package/packages/daemon/src/sessions/tmuxSession.ts +1073 -0
  93. package/packages/daemon/src/sessions/transcriptManager.ts +110 -0
  94. package/packages/daemon/src/sessions/transcriptParser.ts +149 -0
  95. package/packages/daemon/src/sessions/transcriptTailer.ts +214 -0
  96. package/packages/daemon/src/tracking/tokenTracker.ts +168 -0
  97. package/packages/daemon/src/workflows/contextManager.ts +83 -0
  98. package/packages/daemon/src/workflows/index.ts +31 -0
  99. package/packages/daemon/src/workflows/resultExtractor.ts +118 -0
  100. package/packages/daemon/src/workflows/waitConditionPoller.ts +131 -0
  101. package/packages/daemon/src/workflows/workflowParser.ts +217 -0
  102. package/packages/daemon/src/workflows/workflowRunner.ts +969 -0
  103. package/packages/daemon/src/workflows/workflowTypes.ts +188 -0
  104. package/packages/daemon/src/workflows/workflowValidator.ts +533 -0
  105. package/packages/providers/claude-code/package.json +11 -0
  106. package/packages/providers/claude-code/src/index.ts +7 -0
  107. package/packages/providers/claude-code/src/overlaySettings.ts +198 -0
  108. package/packages/providers/claude-code/src/provider.ts +311 -0
  109. package/packages/web/dist/android-chrome-192x192.png +0 -0
  110. package/packages/web/dist/android-chrome-512x512.png +0 -0
  111. package/packages/web/dist/apple-touch-icon.png +0 -0
  112. package/packages/web/dist/assets/AnalyticsPage-BIopKWRf.js +17 -0
  113. package/packages/web/dist/assets/PoliciesPage-CjdLN3dl.js +11 -0
  114. package/packages/web/dist/assets/SessionDetailPage-BtSA0V0M.js +179 -0
  115. package/packages/web/dist/assets/SettingsPage-Dbbz4Ca5.js +37 -0
  116. package/packages/web/dist/assets/WorkflowsPage-Dv6f3GgU.js +1 -0
  117. package/packages/web/dist/assets/chart-vendor-DlOHLaCG.js +49 -0
  118. package/packages/web/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  119. package/packages/web/dist/assets/css.worker-BvV5MPou.js +93 -0
  120. package/packages/web/dist/assets/editor.worker-CKy7Pnvo.js +26 -0
  121. package/packages/web/dist/assets/html.worker-BLJhxQJQ.js +470 -0
  122. package/packages/web/dist/assets/index-BbdhRfr2.css +1 -0
  123. package/packages/web/dist/assets/index-hgphORiw.js +204 -0
  124. package/packages/web/dist/assets/json.worker-usMZ-FED.js +58 -0
  125. package/packages/web/dist/assets/monaco-core-B_19GPAS.css +1 -0
  126. package/packages/web/dist/assets/monaco-core-DQ5Mk8AK.js +1234 -0
  127. package/packages/web/dist/assets/monaco-react-DfZNWvtW.js +11 -0
  128. package/packages/web/dist/assets/monacoSetup-DvBj52bT.js +1 -0
  129. package/packages/web/dist/assets/pencil-Dbczxz59.js +11 -0
  130. package/packages/web/dist/assets/react-vendor-B5MgMUHH.js +136 -0
  131. package/packages/web/dist/assets/refresh-cw-B0MGsYPL.js +6 -0
  132. package/packages/web/dist/assets/tabs-C8LsWiR5.js +1 -0
  133. package/packages/web/dist/assets/terminal-vendor-Cs8KPbV3.js +9 -0
  134. package/packages/web/dist/assets/terminal-vendor-LcAfv9l9.css +32 -0
  135. package/packages/web/dist/assets/trash-2-Btlg0d4l.js +6 -0
  136. package/packages/web/dist/assets/ts.worker-DGHjMaqB.js +67731 -0
  137. package/packages/web/dist/favicon.ico +0 -0
  138. package/packages/web/dist/icon.svg +1 -0
  139. package/packages/web/dist/index.html +29 -0
  140. package/packages/web/dist/manifest.json +29 -0
  141. package/packages/web/dist/og-image.png +0 -0
  142. package/packages/web/dist/originals/android-chrome-192x192.png +0 -0
  143. package/packages/web/dist/originals/android-chrome-512x512.png +0 -0
  144. package/packages/web/dist/originals/apple-touch-icon.png +0 -0
  145. package/packages/web/dist/originals/favicon.ico +0 -0
  146. package/packages/web/dist/piper.svg +1 -0
  147. package/packages/web/dist/sounds/codepiper-soft-chime.wav +0 -0
  148. package/packages/web/dist/sw.js +257 -0
  149. package/scripts/postinstall-link-workspaces.mjs +58 -0
@@ -0,0 +1,257 @@
1
+ const SW_VERSION = new URL(self.location.href).searchParams.get("v") || "dev";
2
+ const CACHE_NAME = `codepiper-v${SW_VERSION}`;
3
+ const PRECACHE = ["/logo.svg"];
4
+ const DEFAULT_NOTIFICATION_TITLE = "CodePiper";
5
+ const DEFAULT_NOTIFICATION_BODY = "A session update is ready.";
6
+ const DEFAULT_NOTIFICATION_URL = "/sessions";
7
+
8
+ function isRecord(value) {
9
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
10
+ }
11
+
12
+ function parsePushPayload(event) {
13
+ if (!event.data) {
14
+ return {};
15
+ }
16
+
17
+ try {
18
+ const parsed = event.data.json();
19
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
20
+ return parsed;
21
+ }
22
+ } catch {
23
+ // Fall through to plain-text payload handling.
24
+ }
25
+
26
+ try {
27
+ const text = event.data.text();
28
+ if (text) {
29
+ return { body: text };
30
+ }
31
+ } catch {
32
+ // Ignore and fallback to defaults.
33
+ }
34
+
35
+ return {};
36
+ }
37
+
38
+ function resolveNotificationUrl(payload) {
39
+ if (typeof payload.url === "string" && payload.url.trim() !== "") {
40
+ return payload.url;
41
+ }
42
+
43
+ if (typeof payload.sessionId === "string" && payload.sessionId.trim() !== "") {
44
+ return `/sessions/${encodeURIComponent(payload.sessionId)}/terminal`;
45
+ }
46
+
47
+ return DEFAULT_NOTIFICATION_URL;
48
+ }
49
+
50
+ function toAbsoluteUrl(urlOrPath) {
51
+ try {
52
+ return new URL(urlOrPath, self.location.origin).toString();
53
+ } catch {
54
+ return new URL(DEFAULT_NOTIFICATION_URL, self.location.origin).toString();
55
+ }
56
+ }
57
+
58
+ async function focusOrOpenClient(urlOrPath) {
59
+ const targetUrl = toAbsoluteUrl(urlOrPath);
60
+ const targetOrigin = new URL(targetUrl).origin;
61
+ const windowClients = await self.clients.matchAll({
62
+ type: "window",
63
+ includeUncontrolled: true,
64
+ });
65
+
66
+ for (const client of windowClients) {
67
+ if (!(client && typeof client.url === "string")) {
68
+ continue;
69
+ }
70
+
71
+ let clientOrigin;
72
+ try {
73
+ clientOrigin = new URL(client.url).origin;
74
+ } catch {
75
+ continue;
76
+ }
77
+
78
+ if (clientOrigin !== targetOrigin) {
79
+ continue;
80
+ }
81
+
82
+ if ("navigate" in client && typeof client.navigate === "function" && client.url !== targetUrl) {
83
+ try {
84
+ await client.navigate(targetUrl);
85
+ } catch {
86
+ // If navigation fails, still attempt to focus the existing client.
87
+ }
88
+ }
89
+
90
+ if (typeof client.focus === "function") {
91
+ await client.focus();
92
+ return;
93
+ }
94
+ }
95
+
96
+ await self.clients.openWindow(targetUrl);
97
+ }
98
+
99
+ async function markNotificationRead(notificationId) {
100
+ if (!Number.isInteger(notificationId)) {
101
+ return;
102
+ }
103
+
104
+ try {
105
+ await fetch(`/api/notifications/${notificationId}/read`, {
106
+ method: "POST",
107
+ headers: {
108
+ "Content-Type": "application/json",
109
+ },
110
+ credentials: "include",
111
+ body: JSON.stringify({ readSource: "click" }),
112
+ });
113
+ } catch {
114
+ // Ignore read-sync failures; navigation is still the primary action.
115
+ }
116
+ }
117
+
118
+ self.addEventListener("install", (e) => {
119
+ e.waitUntil(
120
+ caches
121
+ .open(CACHE_NAME)
122
+ .then((c) => c.addAll(PRECACHE))
123
+ .catch(() => undefined)
124
+ );
125
+ self.skipWaiting();
126
+ });
127
+
128
+ self.addEventListener("activate", (e) => {
129
+ e.waitUntil(
130
+ caches
131
+ .keys()
132
+ .then((keys) =>
133
+ Promise.all(keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k)))
134
+ )
135
+ );
136
+ self.clients.claim();
137
+ });
138
+
139
+ self.addEventListener("push", (event) => {
140
+ const payload = parsePushPayload(event);
141
+ const title =
142
+ typeof payload.title === "string" && payload.title.trim() !== ""
143
+ ? payload.title
144
+ : DEFAULT_NOTIFICATION_TITLE;
145
+ const body =
146
+ typeof payload.body === "string" && payload.body.trim() !== ""
147
+ ? payload.body
148
+ : DEFAULT_NOTIFICATION_BODY;
149
+ const tag =
150
+ typeof payload.tag === "string" && payload.tag.trim() !== ""
151
+ ? payload.tag
152
+ : "codepiper:notification";
153
+ const url = resolveNotificationUrl(payload);
154
+
155
+ event.waitUntil(
156
+ self.registration.showNotification(title, {
157
+ body,
158
+ tag,
159
+ icon: "/apple-touch-icon.png",
160
+ badge: "/logo.svg",
161
+ data: {
162
+ url,
163
+ sessionId: typeof payload.sessionId === "string" ? payload.sessionId : null,
164
+ notificationId: typeof payload.notificationId === "number" ? payload.notificationId : null,
165
+ },
166
+ })
167
+ );
168
+ });
169
+
170
+ self.addEventListener("notificationclick", (event) => {
171
+ event.notification.close();
172
+ const data = event.notification.data;
173
+ const targetUrl =
174
+ data && typeof data.url === "string" && data.url.trim() !== ""
175
+ ? data.url
176
+ : DEFAULT_NOTIFICATION_URL;
177
+ const notificationId =
178
+ data && typeof data.notificationId === "number" ? data.notificationId : null;
179
+ event.waitUntil(
180
+ Promise.all([
181
+ focusOrOpenClient(targetUrl),
182
+ notificationId !== null ? markNotificationRead(notificationId) : Promise.resolve(),
183
+ ])
184
+ );
185
+ });
186
+
187
+ self.addEventListener("message", (event) => {
188
+ if (!(isRecord(event.data) && event.data.type === "SKIP_WAITING")) {
189
+ return;
190
+ }
191
+ self.skipWaiting();
192
+ });
193
+
194
+ self.addEventListener("fetch", (e) => {
195
+ if (e.request.method !== "GET") {
196
+ return;
197
+ }
198
+
199
+ const requestUrl = new URL(e.request.url);
200
+
201
+ if (requestUrl.origin !== self.location.origin) {
202
+ return;
203
+ }
204
+
205
+ // Skip API, WebSocket, and auth routes entirely (never cache)
206
+ if (
207
+ requestUrl.pathname.startsWith("/api/") ||
208
+ requestUrl.pathname === "/ws" ||
209
+ requestUrl.pathname.startsWith("/auth/")
210
+ ) {
211
+ return;
212
+ }
213
+
214
+ // Navigation requests should always prefer fresh HTML to avoid stale mobile PWA shells.
215
+ if (e.request.mode === "navigate") {
216
+ e.respondWith(
217
+ fetch(e.request, { cache: "no-store" }).catch(async () => {
218
+ const cached = await caches.match(e.request);
219
+ return cached || Response.error();
220
+ })
221
+ );
222
+ return;
223
+ }
224
+
225
+ const CACHEABLE_EXTENSIONS = /\.(js|css|png|jpg|jpeg|gif|svg|woff2?|ttf|eot|ico|webmanifest)$/;
226
+ const destination = e.request.destination;
227
+ const isStaticAsset =
228
+ destination === "script" ||
229
+ destination === "style" ||
230
+ destination === "image" ||
231
+ destination === "font" ||
232
+ destination === "manifest" ||
233
+ CACHEABLE_EXTENSIONS.test(requestUrl.pathname);
234
+
235
+ if (!isStaticAsset) {
236
+ return;
237
+ }
238
+
239
+ e.respondWith(
240
+ (async () => {
241
+ const cache = await caches.open(CACHE_NAME);
242
+ try {
243
+ const response = await fetch(e.request);
244
+ if (response.ok) {
245
+ await cache.put(e.request, response.clone());
246
+ }
247
+ return response;
248
+ } catch {
249
+ const cached = await cache.match(e.request);
250
+ if (cached) {
251
+ return cached;
252
+ }
253
+ return Response.error();
254
+ }
255
+ })()
256
+ );
257
+ });
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, lstatSync, mkdirSync, symlinkSync } from "node:fs";
4
+ import { dirname, join, relative, resolve } from "node:path";
5
+ import process from "node:process";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ const ROOT_DIR = resolve(__dirname, "..");
11
+
12
+ const WORKSPACE_LINKS = [
13
+ {
14
+ packageName: "@codepiper/core",
15
+ targetDir: join(ROOT_DIR, "packages/core"),
16
+ },
17
+ {
18
+ packageName: "@codepiper/daemon",
19
+ targetDir: join(ROOT_DIR, "packages/daemon"),
20
+ },
21
+ {
22
+ packageName: "@codepiper/provider-claude-code",
23
+ targetDir: join(ROOT_DIR, "packages/providers/claude-code"),
24
+ },
25
+ ];
26
+
27
+ const SCOPE_DIR = join(ROOT_DIR, "node_modules", "@codepiper");
28
+ const SYMLINK_TYPE = process.platform === "win32" ? "junction" : "dir";
29
+
30
+ function ensureWorkspaceLink(packageName, targetDir) {
31
+ if (!existsSync(targetDir)) {
32
+ return;
33
+ }
34
+
35
+ const packageBasename = packageName.split("/").at(-1);
36
+ if (!packageBasename) {
37
+ return;
38
+ }
39
+
40
+ const linkPath = join(SCOPE_DIR, packageBasename);
41
+ if (existsSync(linkPath)) {
42
+ try {
43
+ // Preserve existing installs (real dirs or existing links).
44
+ lstatSync(linkPath);
45
+ return;
46
+ } catch {
47
+ // Ignore transient race states and continue linking.
48
+ }
49
+ }
50
+
51
+ mkdirSync(SCOPE_DIR, { recursive: true });
52
+ const relativeTarget = relative(dirname(linkPath), targetDir);
53
+ symlinkSync(relativeTarget, linkPath, SYMLINK_TYPE);
54
+ }
55
+
56
+ for (const workspaceLink of WORKSPACE_LINKS) {
57
+ ensureWorkspaceLink(workspaceLink.packageName, workspaceLink.targetDir);
58
+ }