writbase 0.1.0 → 0.1.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.
package/dist/writbase.js CHANGED
@@ -4,17 +4,18 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/commands/init.ts
7
- import { webcrypto } from "crypto";
7
+ import { webcrypto as webcrypto2 } from "crypto";
8
8
  import { execSync } from "child_process";
9
- import { existsSync } from "fs";
10
- import { join as join2 } from "path";
9
+ import { existsSync as existsSync2 } from "fs";
10
+ import { join as join3 } from "path";
11
11
  import { confirm, input, select } from "@inquirer/prompts";
12
12
  import { createSpinner } from "nanospinner";
13
13
 
14
14
  // src/lib/config.ts
15
15
  import dotenv from "dotenv";
16
- import { writeFileSync, renameSync } from "fs";
16
+ import { mkdirSync, writeFileSync, renameSync } from "fs";
17
17
  import { join } from "path";
18
+ import { homedir } from "os";
18
19
 
19
20
  // src/lib/output.ts
20
21
  import pc from "picocolors";
@@ -44,8 +45,9 @@ function table(headers, rows) {
44
45
  }
45
46
 
46
47
  // src/lib/config.ts
48
+ var WRITBASE_HOME = join(homedir(), ".writbase");
47
49
  function loadConfigPartial() {
48
- dotenv.config();
50
+ dotenv.config({ path: join(WRITBASE_HOME, ".env") });
49
51
  return {
50
52
  supabaseUrl: process.env.SUPABASE_URL,
51
53
  supabaseServiceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY,
@@ -68,8 +70,9 @@ function loadConfig() {
68
70
  return partial;
69
71
  }
70
72
  function writeEnv(vars) {
71
- const envPath = join(process.cwd(), ".env");
72
- const tmpPath = join(process.cwd(), ".env.tmp");
73
+ mkdirSync(WRITBASE_HOME, { recursive: true });
74
+ const envPath = join(WRITBASE_HOME, ".env");
75
+ const tmpPath = join(WRITBASE_HOME, ".env.tmp");
73
76
  const content = Object.entries(vars).map(([key2, value]) => `${key2}=${value}`).join("\n") + "\n";
74
77
  writeFileSync(tmpPath, content, { mode: 384 });
75
78
  renameSync(tmpPath, envPath);
@@ -86,15 +89,221 @@ function createAdminClient(url, key2) {
86
89
  });
87
90
  }
88
91
 
92
+ // src/lib/agent-keys.ts
93
+ import { webcrypto } from "crypto";
94
+
95
+ // src/lib/event-log.ts
96
+ async function logEvent(supabase, params) {
97
+ const { error: error2 } = await supabase.from("event_log").insert({
98
+ event_category: params.eventCategory,
99
+ target_type: params.targetType,
100
+ target_id: params.targetId,
101
+ event_type: params.eventType,
102
+ field_name: params.fieldName ?? null,
103
+ old_value: params.oldValue ?? null,
104
+ new_value: params.newValue ?? null,
105
+ actor_type: params.actorType,
106
+ actor_id: params.actorId,
107
+ actor_label: params.actorLabel,
108
+ source: params.source,
109
+ workspace_id: params.workspaceId
110
+ });
111
+ if (error2) {
112
+ console.error(
113
+ "Failed to log event:",
114
+ JSON.stringify({
115
+ event_type: params.eventType,
116
+ target_id: params.targetId,
117
+ error: error2.message
118
+ })
119
+ );
120
+ }
121
+ }
122
+
123
+ // src/lib/agent-keys.ts
124
+ async function hashSecret(secret) {
125
+ const data = new TextEncoder().encode(secret);
126
+ const hashBuffer = await webcrypto.subtle.digest("SHA-256", data);
127
+ return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
128
+ }
129
+ async function generateKey(keyId) {
130
+ const randomBytes = new Uint8Array(32);
131
+ webcrypto.getRandomValues(randomBytes);
132
+ const secret = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
133
+ const hash = await hashSecret(secret);
134
+ const prefix = secret.slice(0, 8);
135
+ const fullKey = `wb_${keyId}_${secret}`;
136
+ return { fullKey, prefix, hash };
137
+ }
138
+ var KEY_COLUMNS = "id, name, role, key_prefix, is_active, special_prompt, created_at, last_used_at, created_by, project_id, department_id";
139
+ async function listAgentKeys(supabase, workspaceId) {
140
+ const { data, error: error2 } = await supabase.from("agent_keys").select(KEY_COLUMNS).eq("workspace_id", workspaceId).order("created_at", { ascending: false });
141
+ if (error2) throw error2;
142
+ return data;
143
+ }
144
+ async function createAgentKey(supabase, params) {
145
+ const keyId = webcrypto.randomUUID();
146
+ const { fullKey, prefix, hash } = await generateKey(keyId);
147
+ const { data, error: error2 } = await supabase.from("agent_keys").insert({
148
+ id: keyId,
149
+ name: params.name,
150
+ role: params.role ?? "worker",
151
+ key_hash: hash,
152
+ key_prefix: prefix,
153
+ special_prompt: null,
154
+ created_by: "writbase-cli",
155
+ workspace_id: params.workspaceId,
156
+ project_id: params.projectId ?? null,
157
+ department_id: params.departmentId ?? null
158
+ }).select(KEY_COLUMNS).single();
159
+ if (error2) throw error2;
160
+ await logEvent(supabase, {
161
+ eventCategory: "admin",
162
+ targetType: "agent_key",
163
+ targetId: data.id,
164
+ eventType: "agent_key.created",
165
+ actorType: "system",
166
+ actorId: "writbase-cli",
167
+ actorLabel: "writbase-cli",
168
+ source: "system",
169
+ workspaceId: params.workspaceId
170
+ });
171
+ return { key: data, fullKey };
172
+ }
173
+ async function rotateAgentKey(supabase, params) {
174
+ const { fullKey, prefix, hash } = await generateKey(params.id);
175
+ const { data, error: error2 } = await supabase.from("agent_keys").update({ key_hash: hash, key_prefix: prefix }).eq("id", params.id).eq("workspace_id", params.workspaceId).select(KEY_COLUMNS).single();
176
+ if (error2) throw error2;
177
+ await logEvent(supabase, {
178
+ eventCategory: "admin",
179
+ targetType: "agent_key",
180
+ targetId: params.id,
181
+ eventType: "agent_key.rotated",
182
+ actorType: "system",
183
+ actorId: "writbase-cli",
184
+ actorLabel: "writbase-cli",
185
+ source: "system",
186
+ workspaceId: params.workspaceId
187
+ });
188
+ return { key: data, fullKey };
189
+ }
190
+ async function deactivateAgentKey(supabase, params) {
191
+ const { data, error: error2 } = await supabase.from("agent_keys").update({ is_active: false }).eq("id", params.id).eq("workspace_id", params.workspaceId).select(KEY_COLUMNS).single();
192
+ if (error2) throw error2;
193
+ await logEvent(supabase, {
194
+ eventCategory: "admin",
195
+ targetType: "agent_key",
196
+ targetId: params.id,
197
+ eventType: "agent_key.deactivated",
198
+ actorType: "system",
199
+ actorId: "writbase-cli",
200
+ actorLabel: "writbase-cli",
201
+ source: "system",
202
+ workspaceId: params.workspaceId
203
+ });
204
+ return data;
205
+ }
206
+
207
+ // src/lib/claude-code.ts
208
+ import { homedir as homedir2 } from "os";
209
+ import { join as join2 } from "path";
210
+ import { fileURLToPath } from "url";
211
+ import { existsSync, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync, renameSync as renameSync2, cpSync } from "fs";
212
+ function generatePluginJson() {
213
+ return JSON.stringify(
214
+ {
215
+ name: "writbase",
216
+ description: "WritBase \u2014 agent-first task management. Skills for MCP tool usage, permissions, and error handling.",
217
+ version: "0.1.2"
218
+ },
219
+ null,
220
+ 2
221
+ );
222
+ }
223
+ function generateMcpJson(mcpUrl, agentKey) {
224
+ return JSON.stringify(
225
+ {
226
+ writbase: {
227
+ type: "http",
228
+ url: mcpUrl,
229
+ headers: {
230
+ Authorization: `Bearer ${agentKey}`
231
+ }
232
+ }
233
+ },
234
+ null,
235
+ 2
236
+ );
237
+ }
238
+ function atomicWriteJson(filePath, content) {
239
+ const tmpPath = filePath + ".tmp";
240
+ writeFileSync2(tmpPath, content);
241
+ renameSync2(tmpPath, filePath);
242
+ }
243
+ function installPlugin(config) {
244
+ const claudeDir = join2(homedir2(), ".claude");
245
+ mkdirSync2(join2(WRITBASE_HOME, ".claude-plugin"), { recursive: true });
246
+ mkdirSync2(join2(WRITBASE_HOME, "skills"), { recursive: true });
247
+ const packageRoot = fileURLToPath(new URL("..", import.meta.url));
248
+ const skillsSource = join2(packageRoot, "skills");
249
+ cpSync(skillsSource, join2(WRITBASE_HOME, "skills"), { recursive: true });
250
+ writeFileSync2(join2(WRITBASE_HOME, ".claude-plugin", "plugin.json"), generatePluginJson());
251
+ const mcpContent = generateMcpJson(config.mcpUrl, config.agentKey);
252
+ const mcpPath = join2(WRITBASE_HOME, ".mcp.json");
253
+ const mcpTmpPath = join2(WRITBASE_HOME, ".mcp.json.tmp");
254
+ writeFileSync2(mcpTmpPath, mcpContent, { mode: 384 });
255
+ renameSync2(mcpTmpPath, mcpPath);
256
+ const pluginsDir = join2(claudeDir, "plugins");
257
+ mkdirSync2(pluginsDir, { recursive: true });
258
+ const marketplacesPath = join2(pluginsDir, "known_marketplaces.json");
259
+ const marketplaces = existsSync(marketplacesPath) ? JSON.parse(readFileSync(marketplacesPath, "utf-8")) : {};
260
+ marketplaces["writbase"] = {
261
+ source: { source: "directory", path: WRITBASE_HOME },
262
+ autoUpdate: false
263
+ };
264
+ atomicWriteJson(marketplacesPath, JSON.stringify(marketplaces, null, 2));
265
+ const settingsPath = join2(claudeDir, "settings.json");
266
+ const settings = existsSync(settingsPath) ? JSON.parse(readFileSync(settingsPath, "utf-8")) : {};
267
+ if (!settings.enabledPlugins) {
268
+ settings.enabledPlugins = {};
269
+ }
270
+ settings.enabledPlugins["writbase@writbase"] = true;
271
+ atomicWriteJson(settingsPath, JSON.stringify(settings, null, 2));
272
+ }
273
+ async function grantBasicPermissions(supabase, params) {
274
+ const perms = {
275
+ agent_key_id: params.keyId,
276
+ project_id: params.projectId,
277
+ workspace_id: params.workspaceId,
278
+ can_read: true,
279
+ can_create: true,
280
+ can_update: true,
281
+ can_assign: params.role === "manager"
282
+ };
283
+ const { error: error2 } = await supabase.from("agent_permissions").insert(perms);
284
+ if (error2) throw error2;
285
+ await logEvent(supabase, {
286
+ eventCategory: "admin",
287
+ targetType: "agent_key",
288
+ targetId: params.keyId,
289
+ eventType: "agent_permission.granted",
290
+ actorType: "system",
291
+ actorId: "writbase-cli",
292
+ actorLabel: "writbase-cli",
293
+ source: "system",
294
+ workspaceId: params.workspaceId
295
+ });
296
+ }
297
+
89
298
  // src/commands/init.ts
90
299
  async function initCommand() {
91
300
  console.log();
92
301
  info("WritBase \u2014 Interactive Setup");
93
302
  console.log();
94
- const envPath = join2(process.cwd(), ".env");
95
- if (existsSync(envPath)) {
303
+ const envPath = join3(WRITBASE_HOME, ".env");
304
+ if (existsSync2(envPath)) {
96
305
  const overwrite = await confirm({
97
- message: ".env file already exists. Reconfigure?",
306
+ message: `${WRITBASE_HOME} already configured. Reconfigure?`,
98
307
  default: false
99
308
  });
100
309
  if (!overwrite) return;
@@ -207,7 +416,7 @@ async function initCommand() {
207
416
  SUPABASE_SERVICE_ROLE_KEY: serviceRoleKey,
208
417
  DATABASE_URL: databaseUrl
209
418
  });
210
- success(".env written (partial \u2014 no workspace yet)");
419
+ success(`Config written to ${WRITBASE_HOME} (partial \u2014 no workspace yet)`);
211
420
  console.log();
212
421
  info("Next steps:");
213
422
  console.log(" 1. writbase migrate");
@@ -236,7 +445,7 @@ async function initCommand() {
236
445
  try {
237
446
  const { data: user, error: userError } = await supabase.auth.admin.createUser({
238
447
  email: "system@writbase.local",
239
- password: webcrypto.randomUUID(),
448
+ password: webcrypto2.randomUUID(),
240
449
  email_confirm: true
241
450
  });
242
451
  let userId;
@@ -279,25 +488,94 @@ async function initCommand() {
279
488
  WRITBASE_WORKSPACE_ID: workspaceId
280
489
  });
281
490
  console.log();
282
- success(".env written");
491
+ success(`Config written to ${WRITBASE_HOME}`);
492
+ console.log();
493
+ const setupClaude = await confirm({
494
+ message: "Set up Claude Code integration? (installs skills + MCP config globally)",
495
+ default: true
496
+ });
497
+ if (setupClaude) {
498
+ const keyName = await input({
499
+ message: "Agent key name:",
500
+ default: "claude-code"
501
+ });
502
+ const keyRole = await select({
503
+ message: "Agent role:",
504
+ choices: [
505
+ { name: "worker", value: "worker" },
506
+ { name: "manager", value: "manager" }
507
+ ],
508
+ default: "worker"
509
+ });
510
+ const { data: projects } = await supabase.from("projects").select("id, name, slug").eq("workspace_id", workspaceId).eq("is_archived", false).order("name");
511
+ let projectId = null;
512
+ if (projects && projects.length > 0) {
513
+ if (projects.length === 1) {
514
+ projectId = projects[0].id;
515
+ info(`Using project: ${projects[0].name} (${projects[0].slug})`);
516
+ } else {
517
+ projectId = await select({
518
+ message: "Grant permissions for project:",
519
+ choices: projects.map((p) => ({
520
+ name: `${p.name} (${p.slug})`,
521
+ value: p.id
522
+ }))
523
+ });
524
+ }
525
+ }
526
+ const mcpUrl = await input({
527
+ message: "MCP endpoint URL:",
528
+ default: `${supabaseUrl}/functions/v1/mcp-server`
529
+ });
530
+ const keySpinner = createSpinner("Creating agent key...").start();
531
+ try {
532
+ const { key: key2, fullKey } = await createAgentKey(supabase, {
533
+ name: keyName.trim() || "claude-code",
534
+ role: keyRole,
535
+ workspaceId,
536
+ projectId
537
+ });
538
+ keySpinner.success({ text: `Agent key created: ${key2.name} (${key2.role})` });
539
+ if (projectId) {
540
+ await grantBasicPermissions(supabase, {
541
+ keyId: key2.id,
542
+ projectId,
543
+ workspaceId,
544
+ role: keyRole
545
+ });
546
+ success("Permissions granted");
547
+ }
548
+ const pluginSpinner = createSpinner("Installing Claude Code plugin...").start();
549
+ installPlugin({ mcpUrl, agentKey: fullKey });
550
+ pluginSpinner.success({ text: "Claude Code plugin installed" });
551
+ console.log();
552
+ warn("Save this agent key \u2014 it cannot be retrieved later:");
553
+ console.log();
554
+ console.log(` ${fullKey}`);
555
+ console.log();
556
+ success("Claude Code integration complete. Restart Claude Code to activate.");
557
+ } catch (err) {
558
+ keySpinner.error({ text: "Claude Code setup failed" });
559
+ error(err instanceof Error ? err.message : String(err));
560
+ console.log();
561
+ info("You can set up Claude Code later with `writbase key create`");
562
+ }
563
+ }
283
564
  console.log();
284
565
  info("Next steps:");
285
- if (!schemaExists) {
286
- console.log(" 1. writbase migrate");
287
- console.log(" 2. writbase key create");
288
- } else {
566
+ if (!setupClaude) {
289
567
  console.log(" 1. writbase key create");
290
568
  }
291
- console.log(" Then: writbase status");
569
+ console.log(" writbase status (verify connection)");
292
570
  console.log();
293
571
  }
294
572
 
295
573
  // src/commands/migrate.ts
296
574
  import { execSync as execSync2 } from "child_process";
297
- import { mkdtempSync, mkdirSync, cpSync, writeFileSync as writeFileSync2, rmSync } from "fs";
298
- import { join as join3 } from "path";
575
+ import { mkdtempSync, mkdirSync as mkdirSync3, cpSync as cpSync2, writeFileSync as writeFileSync3, rmSync } from "fs";
576
+ import { join as join4 } from "path";
299
577
  import { tmpdir } from "os";
300
- import { fileURLToPath } from "url";
578
+ import { fileURLToPath as fileURLToPath2 } from "url";
301
579
  import { createSpinner as createSpinner2 } from "nanospinner";
302
580
  var CONFIG_TOML = `project_id = "writbase"
303
581
 
@@ -319,15 +597,15 @@ async function migrateCommand(opts) {
319
597
  error("Supabase CLI not found. Install it: https://supabase.com/docs/guides/cli");
320
598
  process.exit(1);
321
599
  }
322
- const packageRoot = fileURLToPath(new URL("..", import.meta.url));
323
- const migrationsSource = join3(packageRoot, "migrations");
600
+ const packageRoot = fileURLToPath2(new URL("..", import.meta.url));
601
+ const migrationsSource = join4(packageRoot, "migrations");
324
602
  const spinner = createSpinner2("Running migrations...").start();
325
- const tmpDir = mkdtempSync(join3(tmpdir(), "writbase-migrate-"));
603
+ const tmpDir = mkdtempSync(join4(tmpdir(), "writbase-migrate-"));
326
604
  try {
327
- const supabaseDir = join3(tmpDir, "supabase");
328
- mkdirSync(supabaseDir);
329
- writeFileSync2(join3(supabaseDir, "config.toml"), CONFIG_TOML);
330
- cpSync(migrationsSource, join3(supabaseDir, "migrations"), { recursive: true });
605
+ const supabaseDir = join4(tmpDir, "supabase");
606
+ mkdirSync3(supabaseDir);
607
+ writeFileSync3(join4(supabaseDir, "config.toml"), CONFIG_TOML);
608
+ cpSync2(migrationsSource, join4(supabaseDir, "migrations"), { recursive: true });
331
609
  const args = [`--db-url "${config.databaseUrl}"`, `--workdir ${tmpDir}`];
332
610
  if (opts.dryRun) args.push("--dry-run");
333
611
  const cmd = `supabase migration up ${args.join(" ")}`;
@@ -360,123 +638,6 @@ async function migrateCommand(opts) {
360
638
  // src/commands/key.ts
361
639
  import { confirm as confirm2, input as input2, select as select2 } from "@inquirer/prompts";
362
640
  import { createSpinner as createSpinner3 } from "nanospinner";
363
-
364
- // src/lib/agent-keys.ts
365
- import { webcrypto as webcrypto2 } from "crypto";
366
-
367
- // src/lib/event-log.ts
368
- async function logEvent(supabase, params) {
369
- const { error: error2 } = await supabase.from("event_log").insert({
370
- event_category: params.eventCategory,
371
- target_type: params.targetType,
372
- target_id: params.targetId,
373
- event_type: params.eventType,
374
- field_name: params.fieldName ?? null,
375
- old_value: params.oldValue ?? null,
376
- new_value: params.newValue ?? null,
377
- actor_type: params.actorType,
378
- actor_id: params.actorId,
379
- actor_label: params.actorLabel,
380
- source: params.source,
381
- workspace_id: params.workspaceId
382
- });
383
- if (error2) {
384
- console.error(
385
- "Failed to log event:",
386
- JSON.stringify({
387
- event_type: params.eventType,
388
- target_id: params.targetId,
389
- error: error2.message
390
- })
391
- );
392
- }
393
- }
394
-
395
- // src/lib/agent-keys.ts
396
- async function hashSecret(secret) {
397
- const data = new TextEncoder().encode(secret);
398
- const hashBuffer = await webcrypto2.subtle.digest("SHA-256", data);
399
- return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
400
- }
401
- async function generateKey(keyId) {
402
- const randomBytes = new Uint8Array(32);
403
- webcrypto2.getRandomValues(randomBytes);
404
- const secret = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
405
- const hash = await hashSecret(secret);
406
- const prefix = secret.slice(0, 8);
407
- const fullKey = `wb_${keyId}_${secret}`;
408
- return { fullKey, prefix, hash };
409
- }
410
- var KEY_COLUMNS = "id, name, role, key_prefix, is_active, special_prompt, created_at, last_used_at, created_by, project_id, department_id";
411
- async function listAgentKeys(supabase, workspaceId) {
412
- const { data, error: error2 } = await supabase.from("agent_keys").select(KEY_COLUMNS).eq("workspace_id", workspaceId).order("created_at", { ascending: false });
413
- if (error2) throw error2;
414
- return data;
415
- }
416
- async function createAgentKey(supabase, params) {
417
- const keyId = webcrypto2.randomUUID();
418
- const { fullKey, prefix, hash } = await generateKey(keyId);
419
- const { data, error: error2 } = await supabase.from("agent_keys").insert({
420
- id: keyId,
421
- name: params.name,
422
- role: params.role ?? "worker",
423
- key_hash: hash,
424
- key_prefix: prefix,
425
- special_prompt: null,
426
- created_by: "writbase-cli",
427
- workspace_id: params.workspaceId,
428
- project_id: params.projectId ?? null,
429
- department_id: params.departmentId ?? null
430
- }).select(KEY_COLUMNS).single();
431
- if (error2) throw error2;
432
- await logEvent(supabase, {
433
- eventCategory: "admin",
434
- targetType: "agent_key",
435
- targetId: data.id,
436
- eventType: "agent_key.created",
437
- actorType: "system",
438
- actorId: "writbase-cli",
439
- actorLabel: "writbase-cli",
440
- source: "system",
441
- workspaceId: params.workspaceId
442
- });
443
- return { key: data, fullKey };
444
- }
445
- async function rotateAgentKey(supabase, params) {
446
- const { fullKey, prefix, hash } = await generateKey(params.id);
447
- const { data, error: error2 } = await supabase.from("agent_keys").update({ key_hash: hash, key_prefix: prefix }).eq("id", params.id).eq("workspace_id", params.workspaceId).select(KEY_COLUMNS).single();
448
- if (error2) throw error2;
449
- await logEvent(supabase, {
450
- eventCategory: "admin",
451
- targetType: "agent_key",
452
- targetId: params.id,
453
- eventType: "agent_key.rotated",
454
- actorType: "system",
455
- actorId: "writbase-cli",
456
- actorLabel: "writbase-cli",
457
- source: "system",
458
- workspaceId: params.workspaceId
459
- });
460
- return { key: data, fullKey };
461
- }
462
- async function deactivateAgentKey(supabase, params) {
463
- const { data, error: error2 } = await supabase.from("agent_keys").update({ is_active: false }).eq("id", params.id).eq("workspace_id", params.workspaceId).select(KEY_COLUMNS).single();
464
- if (error2) throw error2;
465
- await logEvent(supabase, {
466
- eventCategory: "admin",
467
- targetType: "agent_key",
468
- targetId: params.id,
469
- eventType: "agent_key.deactivated",
470
- actorType: "system",
471
- actorId: "writbase-cli",
472
- actorLabel: "writbase-cli",
473
- source: "system",
474
- workspaceId: params.workspaceId
475
- });
476
- return data;
477
- }
478
-
479
- // src/commands/key.ts
480
641
  async function resolveKeyByNameOrId(supabase, workspaceId, nameOrId) {
481
642
  const keys = await listAgentKeys(supabase, workspaceId);
482
643
  const byName = keys.find(
@@ -695,7 +856,7 @@ async function statusCommand() {
695
856
 
696
857
  // src/bin/writbase.ts
697
858
  var program = new Command();
698
- program.name("writbase").description("WritBase CLI \u2014 agent-first task management").version("0.1.0");
859
+ program.name("writbase").description("WritBase CLI \u2014 agent-first task management").version("0.1.2");
699
860
  program.command("init").description("Interactive setup \u2014 configure credentials and workspace").action(initCommand);
700
861
  program.command("migrate").description("Apply database migrations via supabase migration up").option("--dry-run", "Show what would be applied without making changes").action(migrateCommand);
701
862
  var key = program.command("key").description("Manage agent keys");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "writbase",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "description": "WritBase CLI — self-hosted operator toolkit for agent-first task management",
6
6
  "bin": {
@@ -8,7 +8,8 @@
8
8
  },
9
9
  "files": [
10
10
  "dist/",
11
- "migrations/"
11
+ "migrations/",
12
+ "skills/"
12
13
  ],
13
14
  "scripts": {
14
15
  "build": "tsup src/bin/writbase.ts --format esm --target node18",