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.
- package/.env.example +28 -0
- package/CHANGELOG.md +10 -0
- package/LEGAL_NOTICE.md +39 -0
- package/LICENSE +21 -0
- package/README.md +524 -0
- package/package.json +90 -0
- package/packages/cli/package.json +13 -0
- package/packages/cli/src/commands/analytics.ts +157 -0
- package/packages/cli/src/commands/attach.ts +299 -0
- package/packages/cli/src/commands/audit.ts +50 -0
- package/packages/cli/src/commands/auth.ts +261 -0
- package/packages/cli/src/commands/daemon.ts +162 -0
- package/packages/cli/src/commands/doctor.ts +303 -0
- package/packages/cli/src/commands/env-set.ts +162 -0
- package/packages/cli/src/commands/hook-forward.ts +268 -0
- package/packages/cli/src/commands/keys.ts +77 -0
- package/packages/cli/src/commands/kill.ts +19 -0
- package/packages/cli/src/commands/logs.ts +419 -0
- package/packages/cli/src/commands/model.ts +172 -0
- package/packages/cli/src/commands/policy-set.ts +185 -0
- package/packages/cli/src/commands/policy.ts +227 -0
- package/packages/cli/src/commands/providers.ts +114 -0
- package/packages/cli/src/commands/resize.ts +34 -0
- package/packages/cli/src/commands/send.ts +184 -0
- package/packages/cli/src/commands/sessions.ts +202 -0
- package/packages/cli/src/commands/slash.ts +92 -0
- package/packages/cli/src/commands/start.ts +243 -0
- package/packages/cli/src/commands/stop.ts +19 -0
- package/packages/cli/src/commands/tail.ts +137 -0
- package/packages/cli/src/commands/workflow.ts +786 -0
- package/packages/cli/src/commands/workspace.ts +127 -0
- package/packages/cli/src/lib/api.ts +78 -0
- package/packages/cli/src/lib/args.ts +72 -0
- package/packages/cli/src/lib/format.ts +93 -0
- package/packages/cli/src/main.ts +563 -0
- package/packages/core/package.json +7 -0
- package/packages/core/src/config.ts +30 -0
- package/packages/core/src/errors.ts +38 -0
- package/packages/core/src/eventBus.ts +56 -0
- package/packages/core/src/eventBusAdapter.ts +143 -0
- package/packages/core/src/index.ts +10 -0
- package/packages/core/src/sqliteEventBus.ts +336 -0
- package/packages/core/src/types.ts +63 -0
- package/packages/daemon/package.json +11 -0
- package/packages/daemon/src/api/analyticsRoutes.ts +343 -0
- package/packages/daemon/src/api/authRoutes.ts +344 -0
- package/packages/daemon/src/api/bodyLimit.ts +133 -0
- package/packages/daemon/src/api/envSetRoutes.ts +170 -0
- package/packages/daemon/src/api/gitRoutes.ts +409 -0
- package/packages/daemon/src/api/hooks.ts +588 -0
- package/packages/daemon/src/api/inputPolicy.ts +249 -0
- package/packages/daemon/src/api/notificationRoutes.ts +532 -0
- package/packages/daemon/src/api/policyRoutes.ts +234 -0
- package/packages/daemon/src/api/policySetRoutes.ts +445 -0
- package/packages/daemon/src/api/routeUtils.ts +28 -0
- package/packages/daemon/src/api/routes.ts +1004 -0
- package/packages/daemon/src/api/server.ts +1388 -0
- package/packages/daemon/src/api/settingsRoutes.ts +367 -0
- package/packages/daemon/src/api/sqliteErrors.ts +47 -0
- package/packages/daemon/src/api/stt.ts +143 -0
- package/packages/daemon/src/api/terminalRoutes.ts +200 -0
- package/packages/daemon/src/api/validation.ts +287 -0
- package/packages/daemon/src/api/validationRoutes.ts +174 -0
- package/packages/daemon/src/api/workflowRoutes.ts +567 -0
- package/packages/daemon/src/api/workspaceRoutes.ts +151 -0
- package/packages/daemon/src/api/ws.ts +1588 -0
- package/packages/daemon/src/auth/apiRateLimiter.ts +73 -0
- package/packages/daemon/src/auth/authMiddleware.ts +305 -0
- package/packages/daemon/src/auth/authService.ts +496 -0
- package/packages/daemon/src/auth/rateLimiter.ts +137 -0
- package/packages/daemon/src/config/pricing.ts +79 -0
- package/packages/daemon/src/crypto/encryption.ts +196 -0
- package/packages/daemon/src/db/db.ts +2745 -0
- package/packages/daemon/src/db/index.ts +16 -0
- package/packages/daemon/src/db/migrations.ts +182 -0
- package/packages/daemon/src/db/policyDb.ts +349 -0
- package/packages/daemon/src/db/schema.sql +408 -0
- package/packages/daemon/src/db/workflowDb.ts +464 -0
- package/packages/daemon/src/git/gitUtils.ts +544 -0
- package/packages/daemon/src/index.ts +6 -0
- package/packages/daemon/src/main.ts +525 -0
- package/packages/daemon/src/notifications/pushNotifier.ts +369 -0
- package/packages/daemon/src/providers/codexAppServerScaffold.ts +49 -0
- package/packages/daemon/src/providers/registry.ts +111 -0
- package/packages/daemon/src/providers/types.ts +82 -0
- package/packages/daemon/src/sessions/auditLogger.ts +103 -0
- package/packages/daemon/src/sessions/policyEngine.ts +165 -0
- package/packages/daemon/src/sessions/policyMatcher.ts +114 -0
- package/packages/daemon/src/sessions/policyTypes.ts +94 -0
- package/packages/daemon/src/sessions/ptyProcess.ts +141 -0
- package/packages/daemon/src/sessions/sessionManager.ts +1770 -0
- package/packages/daemon/src/sessions/tmuxSession.ts +1073 -0
- package/packages/daemon/src/sessions/transcriptManager.ts +110 -0
- package/packages/daemon/src/sessions/transcriptParser.ts +149 -0
- package/packages/daemon/src/sessions/transcriptTailer.ts +214 -0
- package/packages/daemon/src/tracking/tokenTracker.ts +168 -0
- package/packages/daemon/src/workflows/contextManager.ts +83 -0
- package/packages/daemon/src/workflows/index.ts +31 -0
- package/packages/daemon/src/workflows/resultExtractor.ts +118 -0
- package/packages/daemon/src/workflows/waitConditionPoller.ts +131 -0
- package/packages/daemon/src/workflows/workflowParser.ts +217 -0
- package/packages/daemon/src/workflows/workflowRunner.ts +969 -0
- package/packages/daemon/src/workflows/workflowTypes.ts +188 -0
- package/packages/daemon/src/workflows/workflowValidator.ts +533 -0
- package/packages/providers/claude-code/package.json +11 -0
- package/packages/providers/claude-code/src/index.ts +7 -0
- package/packages/providers/claude-code/src/overlaySettings.ts +198 -0
- package/packages/providers/claude-code/src/provider.ts +311 -0
- package/packages/web/dist/android-chrome-192x192.png +0 -0
- package/packages/web/dist/android-chrome-512x512.png +0 -0
- package/packages/web/dist/apple-touch-icon.png +0 -0
- package/packages/web/dist/assets/AnalyticsPage-BIopKWRf.js +17 -0
- package/packages/web/dist/assets/PoliciesPage-CjdLN3dl.js +11 -0
- package/packages/web/dist/assets/SessionDetailPage-BtSA0V0M.js +179 -0
- package/packages/web/dist/assets/SettingsPage-Dbbz4Ca5.js +37 -0
- package/packages/web/dist/assets/WorkflowsPage-Dv6f3GgU.js +1 -0
- package/packages/web/dist/assets/chart-vendor-DlOHLaCG.js +49 -0
- package/packages/web/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
- package/packages/web/dist/assets/css.worker-BvV5MPou.js +93 -0
- package/packages/web/dist/assets/editor.worker-CKy7Pnvo.js +26 -0
- package/packages/web/dist/assets/html.worker-BLJhxQJQ.js +470 -0
- package/packages/web/dist/assets/index-BbdhRfr2.css +1 -0
- package/packages/web/dist/assets/index-hgphORiw.js +204 -0
- package/packages/web/dist/assets/json.worker-usMZ-FED.js +58 -0
- package/packages/web/dist/assets/monaco-core-B_19GPAS.css +1 -0
- package/packages/web/dist/assets/monaco-core-DQ5Mk8AK.js +1234 -0
- package/packages/web/dist/assets/monaco-react-DfZNWvtW.js +11 -0
- package/packages/web/dist/assets/monacoSetup-DvBj52bT.js +1 -0
- package/packages/web/dist/assets/pencil-Dbczxz59.js +11 -0
- package/packages/web/dist/assets/react-vendor-B5MgMUHH.js +136 -0
- package/packages/web/dist/assets/refresh-cw-B0MGsYPL.js +6 -0
- package/packages/web/dist/assets/tabs-C8LsWiR5.js +1 -0
- package/packages/web/dist/assets/terminal-vendor-Cs8KPbV3.js +9 -0
- package/packages/web/dist/assets/terminal-vendor-LcAfv9l9.css +32 -0
- package/packages/web/dist/assets/trash-2-Btlg0d4l.js +6 -0
- package/packages/web/dist/assets/ts.worker-DGHjMaqB.js +67731 -0
- package/packages/web/dist/favicon.ico +0 -0
- package/packages/web/dist/icon.svg +1 -0
- package/packages/web/dist/index.html +29 -0
- package/packages/web/dist/manifest.json +29 -0
- package/packages/web/dist/og-image.png +0 -0
- package/packages/web/dist/originals/android-chrome-192x192.png +0 -0
- package/packages/web/dist/originals/android-chrome-512x512.png +0 -0
- package/packages/web/dist/originals/apple-touch-icon.png +0 -0
- package/packages/web/dist/originals/favicon.ico +0 -0
- package/packages/web/dist/piper.svg +1 -0
- package/packages/web/dist/sounds/codepiper-soft-chime.wav +0 -0
- package/packages/web/dist/sw.js +257 -0
- package/scripts/postinstall-link-workspaces.mjs +58 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database module exports
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
CreateSessionParams,
|
|
7
|
+
EventRecord,
|
|
8
|
+
EventSource,
|
|
9
|
+
GetEventsOptions,
|
|
10
|
+
InsertEventParams,
|
|
11
|
+
ListSessionsOptions,
|
|
12
|
+
TranscriptOffset,
|
|
13
|
+
UpdateSessionParams,
|
|
14
|
+
} from "./db";
|
|
15
|
+
export { Database, type IDatabase } from "./db";
|
|
16
|
+
export { type Migration, MigrationManager } from "./migrations";
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { Database as BunDatabase } from "bun:sqlite";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Migration definition
|
|
5
|
+
*/
|
|
6
|
+
export interface Migration {
|
|
7
|
+
version: number;
|
|
8
|
+
name: string;
|
|
9
|
+
up: (db: BunDatabase) => void;
|
|
10
|
+
down?: (db: BunDatabase) => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Migration manager for schema versioning
|
|
15
|
+
*/
|
|
16
|
+
export class MigrationManager {
|
|
17
|
+
private db: BunDatabase;
|
|
18
|
+
private migrations: Migration[];
|
|
19
|
+
|
|
20
|
+
constructor(db: BunDatabase) {
|
|
21
|
+
this.db = db;
|
|
22
|
+
this.migrations = [];
|
|
23
|
+
this.initMigrationsTable();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create migrations tracking table if it doesn't exist
|
|
28
|
+
*/
|
|
29
|
+
private initMigrationsTable(): void {
|
|
30
|
+
this.db.run(`
|
|
31
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
32
|
+
version INTEGER PRIMARY KEY,
|
|
33
|
+
name TEXT NOT NULL,
|
|
34
|
+
applied_at INTEGER NOT NULL
|
|
35
|
+
)
|
|
36
|
+
`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Register a migration
|
|
41
|
+
*/
|
|
42
|
+
register(migration: Migration): void {
|
|
43
|
+
this.migrations.push(migration);
|
|
44
|
+
// Keep migrations sorted by version
|
|
45
|
+
this.migrations.sort((a, b) => a.version - b.version);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get current schema version
|
|
50
|
+
*/
|
|
51
|
+
getCurrentVersion(): number {
|
|
52
|
+
const stmt = this.db.prepare("SELECT MAX(version) as version FROM schema_migrations");
|
|
53
|
+
const result = stmt.get() as { version: number | null };
|
|
54
|
+
return result.version ?? 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get list of applied migrations
|
|
59
|
+
*/
|
|
60
|
+
getAppliedMigrations(): number[] {
|
|
61
|
+
const stmt = this.db.prepare("SELECT version FROM schema_migrations ORDER BY version");
|
|
62
|
+
const rows = stmt.all() as { version: number }[];
|
|
63
|
+
return rows.map((row) => row.version);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Apply pending migrations
|
|
68
|
+
*/
|
|
69
|
+
migrate(): void {
|
|
70
|
+
const currentVersion = this.getCurrentVersion();
|
|
71
|
+
const pendingMigrations = this.migrations.filter((m) => m.version > currentVersion);
|
|
72
|
+
|
|
73
|
+
if (pendingMigrations.length === 0) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
for (const migration of pendingMigrations) {
|
|
78
|
+
console.log(`Applying migration ${migration.version}: ${migration.name}`);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
migration.up(this.db);
|
|
82
|
+
|
|
83
|
+
// Record migration
|
|
84
|
+
const stmt = this.db.prepare(
|
|
85
|
+
"INSERT INTO schema_migrations (version, name, applied_at) VALUES (?, ?, ?)"
|
|
86
|
+
);
|
|
87
|
+
stmt.run(migration.version, migration.name, Date.now());
|
|
88
|
+
|
|
89
|
+
console.log(`Migration ${migration.version} applied successfully`);
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error(`Migration ${migration.version} failed:`, error);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Rollback migrations to a specific version
|
|
99
|
+
*/
|
|
100
|
+
rollback(targetVersion: number): void {
|
|
101
|
+
const currentVersion = this.getCurrentVersion();
|
|
102
|
+
|
|
103
|
+
if (targetVersion >= currentVersion) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const migrationsToRollback = this.migrations
|
|
108
|
+
.filter((m) => m.version > targetVersion && m.version <= currentVersion)
|
|
109
|
+
.reverse(); // Rollback in reverse order
|
|
110
|
+
|
|
111
|
+
for (const migration of migrationsToRollback) {
|
|
112
|
+
if (!migration.down) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`Migration ${migration.version} (${migration.name}) does not support rollback`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.log(`Rolling back migration ${migration.version}: ${migration.name}`);
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
migration.down(this.db);
|
|
122
|
+
|
|
123
|
+
// Remove migration record
|
|
124
|
+
const stmt = this.db.prepare("DELETE FROM schema_migrations WHERE version = ?");
|
|
125
|
+
stmt.run(migration.version);
|
|
126
|
+
|
|
127
|
+
console.log(`Migration ${migration.version} rolled back successfully`);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
console.error(`Rollback of migration ${migration.version} failed:`, error);
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Reset database to initial state (rollback all migrations)
|
|
137
|
+
*/
|
|
138
|
+
reset(): void {
|
|
139
|
+
this.rollback(0);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Example migration definitions
|
|
145
|
+
*
|
|
146
|
+
* Note: The initial schema is loaded via schema.sql, so migrations
|
|
147
|
+
* are primarily for future schema changes after initial deployment.
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Example: Add index for session timestamps
|
|
152
|
+
*/
|
|
153
|
+
export const migration001: Migration = {
|
|
154
|
+
version: 1,
|
|
155
|
+
name: "add_session_timestamp_index",
|
|
156
|
+
up: (db) => {
|
|
157
|
+
db.run(`
|
|
158
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_created_at
|
|
159
|
+
ON sessions(created_at DESC)
|
|
160
|
+
`);
|
|
161
|
+
},
|
|
162
|
+
down: (db) => {
|
|
163
|
+
db.run("DROP INDEX IF EXISTS idx_sessions_created_at");
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Example: Add index for event timestamps
|
|
169
|
+
*/
|
|
170
|
+
export const migration002: Migration = {
|
|
171
|
+
version: 2,
|
|
172
|
+
name: "add_event_timestamp_index",
|
|
173
|
+
up: (db) => {
|
|
174
|
+
db.run(`
|
|
175
|
+
CREATE INDEX IF NOT EXISTS idx_events_ts
|
|
176
|
+
ON events(ts DESC)
|
|
177
|
+
`);
|
|
178
|
+
},
|
|
179
|
+
down: (db) => {
|
|
180
|
+
db.run("DROP INDEX IF EXISTS idx_events_ts");
|
|
181
|
+
},
|
|
182
|
+
};
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy database operations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { Database } from "./db";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Policy action types
|
|
9
|
+
*/
|
|
10
|
+
export type PolicyAction = "allow" | "deny" | "ask";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Policy rule definition
|
|
14
|
+
*/
|
|
15
|
+
export interface PolicyRule {
|
|
16
|
+
id: string;
|
|
17
|
+
action: PolicyAction;
|
|
18
|
+
tool?: string | string[];
|
|
19
|
+
args?: Record<string, string | string[]>;
|
|
20
|
+
cwd?: string | string[];
|
|
21
|
+
session?: string | string[];
|
|
22
|
+
reason?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Policy record
|
|
27
|
+
*/
|
|
28
|
+
export interface Policy {
|
|
29
|
+
id: string;
|
|
30
|
+
name: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
enabled: boolean;
|
|
33
|
+
priority: number;
|
|
34
|
+
sessionId: string | null;
|
|
35
|
+
rules: PolicyRule[];
|
|
36
|
+
createdAt: Date;
|
|
37
|
+
updatedAt: Date;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Policy decision record
|
|
42
|
+
*/
|
|
43
|
+
export interface PolicyDecision {
|
|
44
|
+
id: number;
|
|
45
|
+
sessionId: string;
|
|
46
|
+
eventId?: number;
|
|
47
|
+
policyId?: string;
|
|
48
|
+
toolName: string;
|
|
49
|
+
args?: Record<string, unknown>;
|
|
50
|
+
decision: PolicyAction;
|
|
51
|
+
reason?: string;
|
|
52
|
+
timestamp: Date;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Policy creation parameters
|
|
57
|
+
*/
|
|
58
|
+
export interface CreatePolicyParams {
|
|
59
|
+
id: string;
|
|
60
|
+
name: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
priority: number;
|
|
64
|
+
sessionId: string | null;
|
|
65
|
+
rules: PolicyRule[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Policy update parameters
|
|
70
|
+
*/
|
|
71
|
+
export interface UpdatePolicyParams {
|
|
72
|
+
name?: string;
|
|
73
|
+
description?: string;
|
|
74
|
+
enabled?: boolean;
|
|
75
|
+
priority?: number;
|
|
76
|
+
rules?: PolicyRule[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Policy query options
|
|
81
|
+
*/
|
|
82
|
+
export interface GetPoliciesOptions {
|
|
83
|
+
enabled?: boolean;
|
|
84
|
+
sessionId?: string | null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Policy decision insertion parameters
|
|
89
|
+
*/
|
|
90
|
+
export interface InsertPolicyDecisionParams {
|
|
91
|
+
sessionId: string;
|
|
92
|
+
eventId?: number;
|
|
93
|
+
policyId?: string;
|
|
94
|
+
toolName: string;
|
|
95
|
+
args?: Record<string, unknown>;
|
|
96
|
+
decision: PolicyAction;
|
|
97
|
+
reason?: string;
|
|
98
|
+
timestamp?: Date;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Policy decision query options
|
|
103
|
+
*/
|
|
104
|
+
export interface GetPolicyDecisionsOptions {
|
|
105
|
+
since?: Date;
|
|
106
|
+
limit?: number;
|
|
107
|
+
decision?: PolicyAction;
|
|
108
|
+
toolName?: string;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Policy database interface
|
|
113
|
+
*/
|
|
114
|
+
export interface PolicyDb {
|
|
115
|
+
// Policy operations
|
|
116
|
+
createPolicy(params: CreatePolicyParams): void;
|
|
117
|
+
getPolicy(id: string): Policy | undefined;
|
|
118
|
+
updatePolicy(id: string, params: UpdatePolicyParams): void;
|
|
119
|
+
deletePolicy(id: string): void;
|
|
120
|
+
getPolicies(options?: GetPoliciesOptions): Policy[];
|
|
121
|
+
|
|
122
|
+
// Policy decision operations
|
|
123
|
+
insertPolicyDecision(params: InsertPolicyDecisionParams): number;
|
|
124
|
+
getPolicyDecisions(sessionId: string, options?: GetPolicyDecisionsOptions): PolicyDecision[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create policy database operations
|
|
129
|
+
*/
|
|
130
|
+
export function createPolicyDb(db: Database): PolicyDb {
|
|
131
|
+
// Get access to underlying Bun database for raw queries
|
|
132
|
+
const bunDb = (db as any).db;
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
/**
|
|
136
|
+
* Create a new policy
|
|
137
|
+
*/
|
|
138
|
+
createPolicy(params: CreatePolicyParams): void {
|
|
139
|
+
const now = Date.now();
|
|
140
|
+
const stmt = bunDb.prepare(`
|
|
141
|
+
INSERT INTO policies (
|
|
142
|
+
id, name, description, enabled, priority, session_id,
|
|
143
|
+
rules_json, created_at, updated_at
|
|
144
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
145
|
+
`);
|
|
146
|
+
|
|
147
|
+
stmt.run(
|
|
148
|
+
params.id,
|
|
149
|
+
params.name,
|
|
150
|
+
params.description ?? null,
|
|
151
|
+
params.enabled ? 1 : 0,
|
|
152
|
+
params.priority,
|
|
153
|
+
params.sessionId,
|
|
154
|
+
JSON.stringify(params.rules),
|
|
155
|
+
now,
|
|
156
|
+
now
|
|
157
|
+
);
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get policy by ID
|
|
162
|
+
*/
|
|
163
|
+
getPolicy(id: string): Policy | undefined {
|
|
164
|
+
const stmt = bunDb.prepare("SELECT * FROM policies WHERE id = ?");
|
|
165
|
+
const row = stmt.get(id) as any;
|
|
166
|
+
|
|
167
|
+
if (!row) return undefined;
|
|
168
|
+
|
|
169
|
+
return mapRowToPolicy(row);
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Update policy fields
|
|
174
|
+
*/
|
|
175
|
+
updatePolicy(id: string, params: UpdatePolicyParams): void {
|
|
176
|
+
const updates: string[] = [];
|
|
177
|
+
const values: unknown[] = [];
|
|
178
|
+
|
|
179
|
+
if (params.name !== undefined) {
|
|
180
|
+
updates.push("name = ?");
|
|
181
|
+
values.push(params.name);
|
|
182
|
+
}
|
|
183
|
+
if (params.description !== undefined) {
|
|
184
|
+
updates.push("description = ?");
|
|
185
|
+
values.push(params.description);
|
|
186
|
+
}
|
|
187
|
+
if (params.enabled !== undefined) {
|
|
188
|
+
updates.push("enabled = ?");
|
|
189
|
+
values.push(params.enabled ? 1 : 0);
|
|
190
|
+
}
|
|
191
|
+
if (params.priority !== undefined) {
|
|
192
|
+
updates.push("priority = ?");
|
|
193
|
+
values.push(params.priority);
|
|
194
|
+
}
|
|
195
|
+
if (params.rules !== undefined) {
|
|
196
|
+
updates.push("rules_json = ?");
|
|
197
|
+
values.push(JSON.stringify(params.rules));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Always update updated_at
|
|
201
|
+
updates.push("updated_at = ?");
|
|
202
|
+
values.push(Date.now());
|
|
203
|
+
|
|
204
|
+
values.push(id);
|
|
205
|
+
|
|
206
|
+
const sql = `UPDATE policies SET ${updates.join(", ")} WHERE id = ?`;
|
|
207
|
+
const stmt = bunDb.prepare(sql);
|
|
208
|
+
stmt.run(...values);
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Delete policy
|
|
213
|
+
*/
|
|
214
|
+
deletePolicy(id: string): void {
|
|
215
|
+
const stmt = bunDb.prepare("DELETE FROM policies WHERE id = ?");
|
|
216
|
+
stmt.run(id);
|
|
217
|
+
},
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get policies with optional filters
|
|
221
|
+
*/
|
|
222
|
+
getPolicies(options: GetPoliciesOptions = {}): Policy[] {
|
|
223
|
+
let sql = "SELECT * FROM policies WHERE 1=1";
|
|
224
|
+
const values: unknown[] = [];
|
|
225
|
+
|
|
226
|
+
if (options.enabled !== undefined) {
|
|
227
|
+
sql += " AND enabled = ?";
|
|
228
|
+
values.push(options.enabled ? 1 : 0);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (options.sessionId !== undefined) {
|
|
232
|
+
if (options.sessionId === null) {
|
|
233
|
+
sql += " AND session_id IS NULL";
|
|
234
|
+
} else {
|
|
235
|
+
sql += " AND session_id = ?";
|
|
236
|
+
values.push(options.sessionId);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Order by priority descending (higher priority first)
|
|
241
|
+
sql += " ORDER BY priority DESC";
|
|
242
|
+
|
|
243
|
+
const stmt = bunDb.prepare(sql);
|
|
244
|
+
const rows = stmt.all(...values) as any[];
|
|
245
|
+
|
|
246
|
+
return rows.map((row) => mapRowToPolicy(row));
|
|
247
|
+
},
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Insert a policy decision
|
|
251
|
+
*/
|
|
252
|
+
insertPolicyDecision(params: InsertPolicyDecisionParams): number {
|
|
253
|
+
const timestamp = params.timestamp ?? new Date();
|
|
254
|
+
const stmt = bunDb.prepare(`
|
|
255
|
+
INSERT INTO policy_decisions (
|
|
256
|
+
session_id, event_id, policy_id, tool_name, args_json,
|
|
257
|
+
decision, reason, timestamp
|
|
258
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
259
|
+
`);
|
|
260
|
+
|
|
261
|
+
stmt.run(
|
|
262
|
+
params.sessionId,
|
|
263
|
+
params.eventId ?? null,
|
|
264
|
+
params.policyId ?? null,
|
|
265
|
+
params.toolName,
|
|
266
|
+
params.args ? JSON.stringify(params.args) : null,
|
|
267
|
+
params.decision,
|
|
268
|
+
params.reason ?? null,
|
|
269
|
+
timestamp.getTime()
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
// Get last inserted row id
|
|
273
|
+
const result = bunDb.query("SELECT last_insert_rowid() as id").get() as { id: number };
|
|
274
|
+
return result.id;
|
|
275
|
+
},
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get policy decisions for a session with optional filters
|
|
279
|
+
*/
|
|
280
|
+
getPolicyDecisions(
|
|
281
|
+
sessionId: string,
|
|
282
|
+
options: GetPolicyDecisionsOptions = {}
|
|
283
|
+
): PolicyDecision[] {
|
|
284
|
+
let sql = "SELECT * FROM policy_decisions WHERE session_id = ?";
|
|
285
|
+
const values: unknown[] = [sessionId];
|
|
286
|
+
|
|
287
|
+
if (options.since !== undefined) {
|
|
288
|
+
sql += " AND timestamp > ?";
|
|
289
|
+
values.push(options.since.getTime());
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (options.decision) {
|
|
293
|
+
sql += " AND decision = ?";
|
|
294
|
+
values.push(options.decision);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (options.toolName) {
|
|
298
|
+
sql += " AND tool_name = ?";
|
|
299
|
+
values.push(options.toolName);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
sql += " ORDER BY id ASC";
|
|
303
|
+
|
|
304
|
+
if (options.limit) {
|
|
305
|
+
sql += " LIMIT ?";
|
|
306
|
+
values.push(options.limit);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const stmt = bunDb.prepare(sql);
|
|
310
|
+
const rows = stmt.all(...values) as any[];
|
|
311
|
+
|
|
312
|
+
return rows.map((row) => mapRowToPolicyDecision(row));
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Map database row to Policy
|
|
319
|
+
*/
|
|
320
|
+
function mapRowToPolicy(row: any): Policy {
|
|
321
|
+
return {
|
|
322
|
+
id: row.id,
|
|
323
|
+
name: row.name,
|
|
324
|
+
description: row.description ?? undefined,
|
|
325
|
+
enabled: row.enabled === 1,
|
|
326
|
+
priority: row.priority,
|
|
327
|
+
sessionId: row.session_id,
|
|
328
|
+
rules: JSON.parse(row.rules_json),
|
|
329
|
+
createdAt: new Date(row.created_at),
|
|
330
|
+
updatedAt: new Date(row.updated_at),
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Map database row to PolicyDecision
|
|
336
|
+
*/
|
|
337
|
+
function mapRowToPolicyDecision(row: any): PolicyDecision {
|
|
338
|
+
return {
|
|
339
|
+
id: row.id,
|
|
340
|
+
sessionId: row.session_id,
|
|
341
|
+
eventId: row.event_id ?? undefined,
|
|
342
|
+
policyId: row.policy_id ?? undefined,
|
|
343
|
+
toolName: row.tool_name,
|
|
344
|
+
args: row.args_json ? JSON.parse(row.args_json) : undefined,
|
|
345
|
+
decision: row.decision as PolicyAction,
|
|
346
|
+
reason: row.reason ?? undefined,
|
|
347
|
+
timestamp: new Date(row.timestamp),
|
|
348
|
+
};
|
|
349
|
+
}
|