@datacore-one/cli 1.0.4 → 1.0.6

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 (2) hide show
  1. package/dist/index.js +770 -301
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -7015,12 +7015,12 @@ async function invokeAgent(invocation, options = {}) {
7015
7015
  error: `Working directory not found: ${cwd}`
7016
7016
  };
7017
7017
  }
7018
- const prompt = buildAgentPrompt(invocation);
7018
+ const prompt2 = buildAgentPrompt(invocation);
7019
7019
  return new Promise((resolve) => {
7020
7020
  const chunks = [];
7021
7021
  let errorChunks = [];
7022
7022
  let timedOut = false;
7023
- const proc = spawn2("claude", ["--print", prompt], {
7023
+ const proc = spawn2("claude", ["--print", prompt2], {
7024
7024
  cwd,
7025
7025
  stdio: ["ignore", "pipe", "pipe"],
7026
7026
  env: {
@@ -7107,9 +7107,9 @@ function listAgents() {
7107
7107
  return [];
7108
7108
  }
7109
7109
  try {
7110
- const { readFileSync: readFileSync6 } = __require("fs");
7110
+ const { readFileSync: readFileSync5 } = __require("fs");
7111
7111
  const { parse: parse3 } = require_dist();
7112
- const content = readFileSync6(registryPath, "utf-8");
7112
+ const content = readFileSync5(registryPath, "utf-8");
7113
7113
  const registry = parse3(content);
7114
7114
  return registry.agents?.map((a) => a.name) || [];
7115
7115
  } catch {
@@ -7991,14 +7991,56 @@ function getVersion(cmd, versionFlag = "--version") {
7991
7991
  return;
7992
7992
  }
7993
7993
  }
7994
- function checkGit(platform2) {
7994
+ function getGitConfig(key) {
7995
+ try {
7996
+ return execSync2(`git config --global ${key}`, { encoding: "utf-8", stdio: "pipe" }).trim();
7997
+ } catch {
7998
+ return;
7999
+ }
8000
+ }
8001
+ function checkGitHubAuth() {
8002
+ try {
8003
+ const output2 = execSync2("gh auth status 2>&1", { encoding: "utf-8", stdio: "pipe" });
8004
+ const userMatch = output2.match(/Logged in to github\.com.*account (\S+)/i);
8005
+ return { authenticated: true, user: userMatch?.[1] };
8006
+ } catch {
8007
+ return { authenticated: false };
8008
+ }
8009
+ }
8010
+ function checkGitDetailed() {
7995
8011
  const installed = commandExists("git");
8012
+ if (!installed) {
8013
+ return { installed: false, configured: false, githubAuth: false };
8014
+ }
8015
+ const userName = getGitConfig("user.name");
8016
+ const userEmail = getGitConfig("user.email");
8017
+ const configured = !!(userName && userEmail);
8018
+ const ghInstalled = commandExists("gh");
8019
+ let githubAuth = false;
8020
+ let githubUser;
8021
+ if (ghInstalled) {
8022
+ const ghStatus = checkGitHubAuth();
8023
+ githubAuth = ghStatus.authenticated;
8024
+ githubUser = ghStatus.user;
8025
+ }
8026
+ return {
8027
+ installed: true,
8028
+ version: getVersion("git"),
8029
+ configured,
8030
+ userName,
8031
+ userEmail,
8032
+ githubAuth,
8033
+ githubUser
8034
+ };
8035
+ }
8036
+ function checkGit(platform2) {
8037
+ const status = checkGitDetailed();
7996
8038
  return {
7997
8039
  name: "git",
7998
8040
  required: true,
7999
- installed,
8000
- version: installed ? getVersion("git") : undefined,
8001
- installCommand: installed ? undefined : getInstallCommand("git", platform2) ?? undefined
8041
+ installed: status.installed,
8042
+ version: status.version,
8043
+ installCommand: status.installed ? undefined : getInstallCommand("git", platform2) ?? undefined
8002
8044
  };
8003
8045
  }
8004
8046
  function checkGitLfs(platform2) {
@@ -8320,7 +8362,28 @@ function createSpace(name, type = "team") {
8320
8362
  throw new Error(`Space already exists: ${folderName}`);
8321
8363
  }
8322
8364
  mkdirSync2(spacePath, { recursive: true });
8323
- const dirs = [
8365
+ const dirs = type === "personal" ? [
8366
+ ".datacore",
8367
+ ".datacore/commands",
8368
+ ".datacore/agents",
8369
+ ".datacore/learning",
8370
+ ".datacore/state",
8371
+ ".datacore/env",
8372
+ "org",
8373
+ "0-inbox",
8374
+ "notes",
8375
+ "notes/journals",
8376
+ "notes/pages",
8377
+ "notes/zettel",
8378
+ "journal",
8379
+ "3-knowledge",
8380
+ "3-knowledge/pages",
8381
+ "3-knowledge/zettel",
8382
+ "3-knowledge/literature",
8383
+ "3-knowledge/reference",
8384
+ "4-archive",
8385
+ "content"
8386
+ ] : [
8324
8387
  ".datacore",
8325
8388
  ".datacore/commands",
8326
8389
  ".datacore/agents",
@@ -8331,6 +8394,11 @@ function createSpace(name, type = "team") {
8331
8394
  "0-inbox",
8332
8395
  "journal",
8333
8396
  "1-tracks",
8397
+ "1-tracks/ops",
8398
+ "1-tracks/product",
8399
+ "1-tracks/dev",
8400
+ "1-tracks/research",
8401
+ "1-tracks/comms",
8334
8402
  "2-projects",
8335
8403
  "3-knowledge",
8336
8404
  "3-knowledge/pages",
@@ -8342,20 +8410,132 @@ function createSpace(name, type = "team") {
8342
8410
  for (const dir of dirs) {
8343
8411
  mkdirSync2(join3(spacePath, dir), { recursive: true });
8344
8412
  }
8345
- writeFileSync2(join3(spacePath, "org", "inbox.org"), `#+TITLE: Inbox
8413
+ if (type === "personal") {
8414
+ writeFileSync2(join3(spacePath, "org", "inbox.org"), `#+TITLE: Inbox
8415
+ #+FILETAGS: :inbox:
8416
+
8417
+ Capture everything here. Process daily to zero.
8418
+
8419
+ * TODO Do more. With less.
8420
+ * Inbox
8421
+ `);
8422
+ writeFileSync2(join3(spacePath, "org", "next_actions.org"), `#+TITLE: Next Actions
8423
+ #+TODO: TODO NEXT WAITING | DONE CANCELED
8424
+ #+FILETAGS: :tasks:
8425
+
8426
+ Tasks organized by focus area. Tag with :AI: to delegate to agents.
8427
+
8428
+ * TIER 1: STRATEGIC FOUNDATION
8429
+ ** /Projects
8430
+ ** /Work
8431
+ * TIER 2: SUPPORTING WORK
8432
+ ** Admin
8433
+ ** Maintenance
8434
+ * PERSONAL: LIFE & DEVELOPMENT
8435
+ ** /Personal Development
8436
+ ** /Health & Longevity
8437
+ ** Home & Family
8438
+ ** Financial Management
8439
+ * RESEARCH & LEARNING
8440
+ ** Technology
8441
+ ** Skills
8442
+ `);
8443
+ writeFileSync2(join3(spacePath, "org", "nightshift.org"), `#+TITLE: Nightshift Queue
8444
+ #+TODO: QUEUED EXECUTING | DONE FAILED
8445
+ #+FILETAGS: :nightshift:
8446
+
8447
+ AI tasks queued for overnight execution. Managed by /tomorrow command.
8448
+
8449
+ * Queue
8450
+ `);
8451
+ writeFileSync2(join3(spacePath, "org", "habits.org"), `#+TITLE: Habits
8452
+ #+FILETAGS: :habits:
8453
+
8454
+ Recurring behaviors and routines. Track with org-habit.
8455
+
8456
+ * Daily
8457
+ * Weekly
8458
+ * Monthly
8459
+ `);
8460
+ writeFileSync2(join3(spacePath, "org", "someday.org"), `#+TITLE: Someday/Maybe
8461
+ #+FILETAGS: :someday:
8462
+
8463
+ Ideas and projects for the future. Review monthly.
8464
+
8465
+ * Someday
8466
+ * Maybe
8467
+ `);
8468
+ writeFileSync2(join3(spacePath, "org", "archive.org"), `#+TITLE: Archive
8469
+ #+FILETAGS: :archive:
8470
+
8471
+ Completed and canceled tasks. Searchable history.
8472
+
8473
+ * Archived Tasks
8474
+ `);
8475
+ } else {
8476
+ writeFileSync2(join3(spacePath, "org", "inbox.org"), `#+TITLE: Inbox
8346
8477
  #+FILETAGS: :inbox:
8347
8478
 
8348
8479
  * Capture items here
8349
8480
  `);
8350
- writeFileSync2(join3(spacePath, "org", "next_actions.org"), `#+TITLE: Next Actions
8481
+ writeFileSync2(join3(spacePath, "org", "next_actions.org"), `#+TITLE: Next Actions
8351
8482
  #+FILETAGS: :tasks:
8352
8483
 
8353
8484
  * Tasks
8354
8485
  ** TODO items go here
8355
8486
  `);
8356
- writeFileSync2(join3(spacePath, "_index.md"), `# ${name}
8487
+ }
8488
+ if (type === "personal") {
8489
+ writeFileSync2(join3(spacePath, "_index.md"), `# Personal Space
8490
+
8491
+ Your personal knowledge base and GTD system.
8492
+
8493
+ ## GTD Workflow
8357
8494
 
8358
- ${type === "personal" ? "Personal" : "Team"} space.
8495
+ 1. **Capture** \`org/inbox.org\` - dump everything here
8496
+ 2. **Clarify** → Is it actionable? What's the next action?
8497
+ 3. **Organize** → Move to \`next_actions.org\` by focus area
8498
+ 4. **Reflect** → Weekly review, monthly strategic
8499
+ 5. **Engage** → Do the work, delegate with :AI: tags
8500
+
8501
+ ## Org Files (GTD)
8502
+
8503
+ | File | Purpose |
8504
+ |------|---------|
8505
+ | [inbox.org](org/inbox.org) | Single capture point - process to zero daily |
8506
+ | [next_actions.org](org/next_actions.org) | Active tasks by focus area |
8507
+ | [nightshift.org](org/nightshift.org) | AI task queue (overnight processing) |
8508
+ | [habits.org](org/habits.org) | Recurring behaviors |
8509
+ | [someday.org](org/someday.org) | Future possibilities |
8510
+ | [archive.org](org/archive.org) | Completed/canceled tasks |
8511
+
8512
+ ## Knowledge
8513
+
8514
+ | Folder | Purpose |
8515
+ |--------|---------|
8516
+ | [notes/](notes/) | Personal knowledge base (Obsidian) |
8517
+ | [notes/journals/](notes/journals/) | Daily personal journals |
8518
+ | [3-knowledge/](3-knowledge/) | Structured knowledge (zettelkasten) |
8519
+
8520
+ ## Other
8521
+
8522
+ - [journal/](journal/) - AI session journals (auto-generated)
8523
+ - [content/](content/) - Generated content (drafts, emails)
8524
+ - [0-inbox/](0-inbox/) - File inbox (process files here)
8525
+ - [4-archive/](4-archive/) - Historical content
8526
+ `);
8527
+ } else {
8528
+ writeFileSync2(join3(spacePath, "_index.md"), `# ${name}
8529
+
8530
+ Team space.
8531
+
8532
+ ## Structure
8533
+
8534
+ - \`org/\` - Task coordination
8535
+ - \`1-tracks/\` - Department work
8536
+ - \`2-projects/\` - Code repositories
8537
+ - \`3-knowledge/\` - Shared knowledge
8538
+ - \`4-archive/\` - Historical content
8359
8539
 
8360
8540
  ## Quick Links
8361
8541
 
@@ -8364,14 +8544,75 @@ ${type === "personal" ? "Personal" : "Team"} space.
8364
8544
  - [Journal](journal/)
8365
8545
  - [Knowledge](3-knowledge/)
8366
8546
  `);
8367
- writeFileSync2(join3(spacePath, "CLAUDE.base.md"), `# ${name} Space
8547
+ }
8548
+ if (type === "personal") {
8549
+ writeFileSync2(join3(spacePath, "CLAUDE.base.md"), `# Personal Space
8550
+
8551
+ Personal GTD system and knowledge base (per DIP-0009).
8368
8552
 
8369
- ${type === "personal" ? "Personal" : "Team"} space for ${name}.
8553
+ ## GTD Files
8554
+
8555
+ | File | Purpose | Process |
8556
+ |------|---------|---------|
8557
+ | \`org/inbox.org\` | Single capture point | Process to zero daily |
8558
+ | \`org/next_actions.org\` | Active tasks by focus area | Work from here |
8559
+ | \`org/nightshift.org\` | AI task queue | Auto-managed by /tomorrow |
8560
+ | \`org/habits.org\` | Recurring behaviors | Track daily |
8561
+ | \`org/someday.org\` | Future possibilities | Review monthly |
8562
+ | \`org/archive.org\` | Completed tasks | Searchable history |
8563
+
8564
+ ## Task States
8565
+
8566
+ | State | Meaning |
8567
+ |-------|---------|
8568
+ | \`TODO\` | Standard next action |
8569
+ | \`NEXT\` | High priority, work today |
8570
+ | \`WAITING\` | Blocked on external |
8571
+ | \`DONE\` | Completed (terminal) |
8572
+ | \`CANCELED\` | Will not do (terminal) |
8573
+
8574
+ ## AI Delegation
8575
+
8576
+ Tag tasks with \`:AI:\` to delegate to agents:
8577
+
8578
+ | Tag | Agent | Autonomous |
8579
+ |-----|-------|------------|
8580
+ | \`:AI:content:\` | gtd-content-writer | Yes |
8581
+ | \`:AI:research:\` | gtd-research-processor | Yes |
8582
+ | \`:AI:data:\` | gtd-data-analyzer | Yes |
8583
+ | \`:AI:pm:\` | gtd-project-manager | Yes |
8584
+
8585
+ ## Knowledge Structure
8586
+
8587
+ | Location | Purpose |
8588
+ |----------|---------|
8589
+ | \`notes/\` | Personal knowledge base (Obsidian) |
8590
+ | \`notes/journals/\` | Daily personal reflections |
8591
+ | \`3-knowledge/zettel/\` | Atomic concept notes |
8592
+ | \`3-knowledge/literature/\` | Source summaries |
8593
+
8594
+ ## Daily Workflow
8595
+
8596
+ 1. **Morning** - Run \`/today\` for briefing
8597
+ 2. **Capture** - Everything to inbox.org
8598
+ 3. **Process** - Clear inbox, route tasks
8599
+ 4. **Work** - Focus on NEXT items
8600
+ 5. **Evening** - Run \`/tomorrow\` for wrap-up
8601
+
8602
+ ## See Also
8603
+
8604
+ Parent: ~/Data/CLAUDE.md
8605
+ `);
8606
+ } else {
8607
+ writeFileSync2(join3(spacePath, "CLAUDE.base.md"), `# ${name} Space
8608
+
8609
+ Team space for ${name}.
8370
8610
 
8371
8611
  ## Structure
8372
8612
 
8373
8613
  See parent CLAUDE.md for full documentation.
8374
8614
  `);
8615
+ }
8375
8616
  writeFileSync2(join3(spacePath, ".datacore", "config.yaml"), `# Space configuration
8376
8617
  name: ${normalizedName}
8377
8618
  type: ${type}
@@ -8388,7 +8629,11 @@ Human feedback log.
8388
8629
 
8389
8630
  Style and preference notes.
8390
8631
  `);
8391
- writeFileSync2(join3(spacePath, ".gitignore"), `.datacore/state/
8632
+ writeFileSync2(join3(spacePath, ".gitignore"), type === "personal" ? `.datacore/state/
8633
+ .datacore/env/
8634
+ CLAUDE.md
8635
+ CLAUDE.local.md
8636
+ ` : `.datacore/state/
8392
8637
  .datacore/env/
8393
8638
  CLAUDE.md
8394
8639
  CLAUDE.local.md
@@ -8539,26 +8784,193 @@ function getGitRepos() {
8539
8784
  }
8540
8785
 
8541
8786
  // src/lib/init.ts
8542
- import { existsSync as existsSync6, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, symlinkSync } from "fs";
8543
- import { join as join6 } from "path";
8787
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, symlinkSync } from "fs";
8788
+ import { join as join7 } from "path";
8789
+ import { createInterface } from "readline";
8790
+
8791
+ // src/lib/module.ts
8792
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync2, rmSync } from "fs";
8793
+ import { join as join5, basename as basename3 } from "path";
8794
+ import { execSync as execSync4 } from "child_process";
8795
+ var DATA_DIR4 = join5(process.env.HOME || "~", "Data");
8796
+ var MODULES_DIR = join5(DATA_DIR4, ".datacore", "modules");
8797
+ var AVAILABLE_MODULES = [
8798
+ {
8799
+ name: "nightshift",
8800
+ description: "Overnight AI task execution",
8801
+ repo: "https://github.com/datacore-one/module-nightshift",
8802
+ features: ["Queues :AI: tasks for overnight processing", "Morning briefing with results", "Remote server support"]
8803
+ },
8804
+ {
8805
+ name: "crm",
8806
+ description: "Contact relationship management",
8807
+ repo: "https://github.com/datacore-one/module-crm",
8808
+ features: ["Contact profiles", "Interaction history", "Relationship tracking"]
8809
+ },
8810
+ {
8811
+ name: "meetings",
8812
+ description: "Meeting preparation and follow-up",
8813
+ repo: "https://github.com/datacore-one/module-meetings",
8814
+ features: ["Pre-meeting briefs", "Transcript processing", "Action item extraction"]
8815
+ },
8816
+ {
8817
+ name: "health",
8818
+ description: "Personal health and wellness tracking",
8819
+ repo: "https://github.com/datacore-one/module-health",
8820
+ features: ["Health metrics", "Habit tracking", "Wellness insights"]
8821
+ }
8822
+ ];
8823
+ function getAvailableModules() {
8824
+ const installed = listModules().map((m) => m.name);
8825
+ return AVAILABLE_MODULES.filter((m) => !installed.includes(m.name));
8826
+ }
8827
+ function listModules() {
8828
+ if (!existsSync5(MODULES_DIR)) {
8829
+ return [];
8830
+ }
8831
+ const entries = readdirSync2(MODULES_DIR, { withFileTypes: true });
8832
+ const modules = [];
8833
+ for (const entry of entries) {
8834
+ if (!entry.isDirectory())
8835
+ continue;
8836
+ if (entry.name.startsWith("."))
8837
+ continue;
8838
+ const modulePath = join5(MODULES_DIR, entry.name);
8839
+ const info2 = getModuleInfo(modulePath);
8840
+ if (info2) {
8841
+ modules.push(info2);
8842
+ }
8843
+ }
8844
+ return modules;
8845
+ }
8846
+ function getModuleInfo(modulePath) {
8847
+ const name = basename3(modulePath);
8848
+ const yamlPath = join5(modulePath, "module.yaml");
8849
+ const ymlPath = join5(modulePath, "module.yml");
8850
+ const configPath = existsSync5(yamlPath) ? yamlPath : existsSync5(ymlPath) ? ymlPath : null;
8851
+ let version;
8852
+ let description;
8853
+ if (configPath) {
8854
+ try {
8855
+ const { parse: parse2 } = require_dist();
8856
+ const content = readFileSync2(configPath, "utf-8");
8857
+ const config = parse2(content);
8858
+ version = config.version;
8859
+ description = config.description;
8860
+ } catch {}
8861
+ }
8862
+ const agentsDir = join5(modulePath, "agents");
8863
+ const agents = [];
8864
+ if (existsSync5(agentsDir)) {
8865
+ const agentFiles = readdirSync2(agentsDir);
8866
+ for (const file of agentFiles) {
8867
+ if (file.endsWith(".md")) {
8868
+ agents.push(file.replace(".md", ""));
8869
+ }
8870
+ }
8871
+ }
8872
+ const commandsDir = join5(modulePath, "commands");
8873
+ const commands = [];
8874
+ if (existsSync5(commandsDir)) {
8875
+ const cmdFiles = readdirSync2(commandsDir);
8876
+ for (const file of cmdFiles) {
8877
+ if (file.endsWith(".md")) {
8878
+ commands.push(file.replace(".md", ""));
8879
+ }
8880
+ }
8881
+ }
8882
+ return {
8883
+ name,
8884
+ path: modulePath,
8885
+ version,
8886
+ description,
8887
+ agents,
8888
+ commands
8889
+ };
8890
+ }
8891
+ function installModule(source) {
8892
+ if (!existsSync5(MODULES_DIR)) {
8893
+ const { mkdirSync: mkdirSync3 } = __require("fs");
8894
+ mkdirSync3(MODULES_DIR, { recursive: true });
8895
+ }
8896
+ let name;
8897
+ let isGit = false;
8898
+ if (source.includes("github.com") || source.startsWith("git@") || source.endsWith(".git")) {
8899
+ isGit = true;
8900
+ const match = source.match(/([^/]+?)(?:\.git)?$/);
8901
+ name = match?.[1] ?? source.split("/").pop() ?? "unknown";
8902
+ name = name.replace(/^module-/, "");
8903
+ } else if (source.startsWith("@")) {
8904
+ name = source.split("/").pop()?.replace(/^datacore-/, "") ?? "unknown";
8905
+ } else {
8906
+ name = source.replace(/^datacore-/, "").replace(/^module-/, "");
8907
+ }
8908
+ const modulePath = join5(MODULES_DIR, name);
8909
+ if (existsSync5(modulePath)) {
8910
+ throw new Error(`Module already installed: ${name}`);
8911
+ }
8912
+ if (isGit) {
8913
+ execSync4(`git clone ${source} "${modulePath}"`, { stdio: "pipe" });
8914
+ } else {
8915
+ const gitUrl = `https://github.com/datacore/module-${name}.git`;
8916
+ try {
8917
+ execSync4(`git clone ${gitUrl} "${modulePath}"`, { stdio: "pipe" });
8918
+ } catch {
8919
+ throw new Error(`Could not install module: ${source}`);
8920
+ }
8921
+ }
8922
+ const info2 = getModuleInfo(modulePath);
8923
+ if (!info2) {
8924
+ rmSync(modulePath, { recursive: true, force: true });
8925
+ throw new Error("Invalid module: missing module.yaml");
8926
+ }
8927
+ return info2;
8928
+ }
8929
+ function updateModules(name) {
8930
+ const modules = listModules();
8931
+ const results = [];
8932
+ const toUpdate = name ? modules.filter((m) => m.name === name) : modules;
8933
+ for (const mod of toUpdate) {
8934
+ try {
8935
+ const gitDir = join5(mod.path, ".git");
8936
+ if (existsSync5(gitDir)) {
8937
+ execSync4("git pull", { cwd: mod.path, stdio: "pipe" });
8938
+ results.push({ name: mod.name, updated: true });
8939
+ } else {
8940
+ results.push({ name: mod.name, updated: false, error: "Not a git repository" });
8941
+ }
8942
+ } catch (err) {
8943
+ results.push({ name: mod.name, updated: false, error: err.message });
8944
+ }
8945
+ }
8946
+ return results;
8947
+ }
8948
+ function removeModule(name) {
8949
+ const modulePath = join5(MODULES_DIR, name);
8950
+ if (!existsSync5(modulePath)) {
8951
+ return false;
8952
+ }
8953
+ rmSync(modulePath, { recursive: true, force: true });
8954
+ return true;
8955
+ }
8544
8956
 
8545
8957
  // src/state.ts
8546
- import { existsSync as existsSync5, mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "fs";
8547
- import { join as join5 } from "path";
8548
- var STATE_DIR = join5(process.env.HOME || "~", "Data", ".datacore", "state");
8549
- var STATE_FILE = join5(STATE_DIR, "operations.json");
8958
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
8959
+ import { join as join6 } from "path";
8960
+ var STATE_DIR = join6(process.env.HOME || "~", "Data", ".datacore", "state");
8961
+ var STATE_FILE = join6(STATE_DIR, "operations.json");
8550
8962
  function ensureStateDir() {
8551
- if (!existsSync5(STATE_DIR)) {
8963
+ if (!existsSync6(STATE_DIR)) {
8552
8964
  mkdirSync3(STATE_DIR, { recursive: true });
8553
8965
  }
8554
8966
  }
8555
8967
  function loadState() {
8556
8968
  ensureStateDir();
8557
- if (!existsSync5(STATE_FILE)) {
8969
+ if (!existsSync6(STATE_FILE)) {
8558
8970
  return { operations: [] };
8559
8971
  }
8560
8972
  try {
8561
- const content = readFileSync2(STATE_FILE, "utf-8");
8973
+ const content = readFileSync3(STATE_FILE, "utf-8");
8562
8974
  return JSON.parse(content);
8563
8975
  } catch {
8564
8976
  return { operations: [] };
@@ -8651,6 +9063,7 @@ function startOperation(operation, params = {}) {
8651
9063
  }
8652
9064
 
8653
9065
  // src/lib/animation.ts
9066
+ var SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
8654
9067
  var c = {
8655
9068
  reset: "\x1B[0m",
8656
9069
  bright: "\x1B[1m",
@@ -8686,6 +9099,44 @@ ${c.green}${c.bright}
8686
9099
  ╚═══════════════════════════════════════════════════════════════╝
8687
9100
  ${c.reset}
8688
9101
  `;
9102
+ function sleep(ms) {
9103
+ return new Promise((resolve) => setTimeout(resolve, ms));
9104
+ }
9105
+ class Spinner {
9106
+ interval = null;
9107
+ frame = 0;
9108
+ message;
9109
+ constructor(message) {
9110
+ this.message = message;
9111
+ }
9112
+ start() {
9113
+ process.stdout.write("\x1B[?25l");
9114
+ this.interval = setInterval(() => {
9115
+ const spinner = SPINNER_FRAMES[this.frame % SPINNER_FRAMES.length];
9116
+ process.stdout.write(`\r${c.cyan}${spinner}${c.reset} ${this.message}`);
9117
+ this.frame++;
9118
+ }, 80);
9119
+ }
9120
+ update(message) {
9121
+ this.message = message;
9122
+ }
9123
+ succeed(message) {
9124
+ this.stop();
9125
+ console.log(`\r${c.green}✓${c.reset} ${message || this.message}`);
9126
+ }
9127
+ fail(message) {
9128
+ this.stop();
9129
+ console.log(`\r${c.yellow}✗${c.reset} ${message || this.message}`);
9130
+ }
9131
+ stop() {
9132
+ if (this.interval) {
9133
+ clearInterval(this.interval);
9134
+ this.interval = null;
9135
+ }
9136
+ process.stdout.write("\x1B[?25h");
9137
+ process.stdout.write("\r" + " ".repeat(this.message.length + 10) + "\r");
9138
+ }
9139
+ }
8689
9140
  function section(title) {
8690
9141
  console.log();
8691
9142
  console.log(`${c.cyan}${c.bright}▸ ${title}${c.reset}`);
@@ -8693,20 +9144,53 @@ function section(title) {
8693
9144
  }
8694
9145
 
8695
9146
  // src/lib/init.ts
8696
- var DATA_DIR4 = join6(process.env.HOME || "~", "Data");
8697
- var DATACORE_DIR = join6(DATA_DIR4, ".datacore");
9147
+ var DATA_DIR5 = join7(process.env.HOME || "~", "Data");
9148
+ var DATACORE_DIR = join7(DATA_DIR5, ".datacore");
9149
+ var c2 = {
9150
+ reset: "\x1B[0m",
9151
+ bold: "\x1B[1m",
9152
+ dim: "\x1B[2m",
9153
+ green: "\x1B[32m",
9154
+ yellow: "\x1B[33m",
9155
+ red: "\x1B[31m",
9156
+ cyan: "\x1B[36m",
9157
+ magenta: "\x1B[35m"
9158
+ };
9159
+ async function prompt(question, defaultValue) {
9160
+ const rl = createInterface({
9161
+ input: process.stdin,
9162
+ output: process.stdout
9163
+ });
9164
+ return new Promise((resolve) => {
9165
+ const defaultHint = defaultValue ? ` [${defaultValue}]` : "";
9166
+ rl.question(`${question}${defaultHint}: `, (answer) => {
9167
+ rl.close();
9168
+ resolve(answer.trim() || defaultValue || "");
9169
+ });
9170
+ });
9171
+ }
9172
+ async function confirm(question, defaultYes = true) {
9173
+ const hint = defaultYes ? "[Y/n]" : "[y/N]";
9174
+ const answer = await prompt(`${question} ${hint}`);
9175
+ if (!answer)
9176
+ return defaultYes;
9177
+ return answer.toLowerCase().startsWith("y");
9178
+ }
8698
9179
  function isInitialized() {
8699
- return existsSync6(DATACORE_DIR);
9180
+ return existsSync7(DATACORE_DIR);
8700
9181
  }
8701
9182
  async function initDatacore(options = {}) {
8702
9183
  const { nonInteractive = false, skipChecks = false, stream = false } = options;
8703
9184
  const isTTY = stream && process.stdout.isTTY;
9185
+ const interactive = isTTY && !nonInteractive;
8704
9186
  const result = {
8705
9187
  success: false,
8706
9188
  created: [],
8707
9189
  warnings: [],
8708
9190
  errors: [],
8709
- nextSteps: []
9191
+ nextSteps: [],
9192
+ spacesCreated: [],
9193
+ modulesInstalled: []
8710
9194
  };
8711
9195
  const op = startOperation("init", { options });
8712
9196
  op.start();
@@ -8714,42 +9198,63 @@ async function initDatacore(options = {}) {
8714
9198
  if (isTTY) {
8715
9199
  console.clear();
8716
9200
  console.log(BANNER);
9201
+ console.log(` ${c2.dim}Setting up your AI-powered second brain...${c2.reset}`);
8717
9202
  console.log();
9203
+ await sleep(300);
8718
9204
  }
8719
- const TOTAL_STEPS = 6;
8720
9205
  op.addStep("check_dependencies");
8721
9206
  op.startStep("check_dependencies");
8722
9207
  if (!skipChecks) {
8723
9208
  if (isTTY) {
8724
- section("Checking Dependencies");
8725
- console.log(" \x1B[90mDatacore requires a few tools to manage your knowledge system.\x1B[0m");
9209
+ section("Step 1: Checking Your System");
8726
9210
  console.log();
8727
9211
  }
8728
9212
  const doctor = runDoctor();
8729
- const depInfo = {
8730
- git: "Version control for your knowledge repos",
8731
- "git-lfs": "Large file support (PDFs, images, videos)",
8732
- node: "Runtime for CLI tools and automation",
8733
- python: "Powers AI agents and data processing",
8734
- claude: "Claude Code AI assistant integration"
8735
- };
9213
+ const gitStatus = checkGitDetailed();
8736
9214
  if (isTTY) {
9215
+ if (gitStatus.installed) {
9216
+ console.log(` ${c2.green}✓${c2.reset} git ${c2.dim}(${gitStatus.version})${c2.reset}`);
9217
+ if (gitStatus.configured) {
9218
+ console.log(` ${c2.dim}Configured as: ${gitStatus.userName} <${gitStatus.userEmail}>${c2.reset}`);
9219
+ } else {
9220
+ console.log(` ${c2.yellow}⚠${c2.reset} ${c2.yellow}Not configured. Run:${c2.reset}`);
9221
+ console.log(` ${c2.dim}git config --global user.name "Your Name"${c2.reset}`);
9222
+ console.log(` ${c2.dim}git config --global user.email "you@example.com"${c2.reset}`);
9223
+ result.warnings.push("git not configured with user.name and user.email");
9224
+ }
9225
+ } else {
9226
+ console.log(` ${c2.red}✗${c2.reset} git ${c2.red}(required)${c2.reset}`);
9227
+ console.log(` ${c2.dim}Version control for your knowledge system${c2.reset}`);
9228
+ result.errors.push("git is required but not installed");
9229
+ }
9230
+ if (gitStatus.githubAuth) {
9231
+ console.log(` ${c2.green}✓${c2.reset} GitHub ${c2.dim}(authenticated as ${gitStatus.githubUser})${c2.reset}`);
9232
+ } else {
9233
+ console.log(` ${c2.yellow}○${c2.reset} GitHub ${c2.dim}(not authenticated)${c2.reset}`);
9234
+ console.log(` ${c2.dim}Optional: Install gh CLI and run 'gh auth login'${c2.reset}`);
9235
+ }
8737
9236
  for (const dep of doctor.dependencies) {
8738
- const info2 = depInfo[dep.name] || "";
9237
+ if (dep.name === "git")
9238
+ continue;
9239
+ const info2 = {
9240
+ "git-lfs": "Large file support (PDFs, images, videos)",
9241
+ node: "Runtime for automation scripts",
9242
+ python: "Powers AI agents and data processing",
9243
+ claude: "Claude Code AI assistant"
9244
+ };
8739
9245
  if (dep.installed) {
8740
- console.log(` \x1B[32m✓\x1B[0m ${dep.name} ${dep.version ? `\x1B[90m(${dep.version})\x1B[0m` : ""}`);
8741
- console.log(` \x1B[90m${info2}\x1B[0m`);
9246
+ console.log(` ${c2.green}✓${c2.reset} ${dep.name} ${dep.version ? `${c2.dim}(${dep.version})${c2.reset}` : ""}`);
8742
9247
  } else if (dep.required) {
8743
- console.log(` \x1B[31m✗\x1B[0m ${dep.name} \x1B[31m(required)\x1B[0m`);
8744
- console.log(` \x1B[90m${info2}\x1B[0m`);
9248
+ console.log(` ${c2.red}✗${c2.reset} ${dep.name} ${c2.red}(required)${c2.reset}`);
9249
+ console.log(` ${c2.dim}${info2[dep.name] || ""}${c2.reset}`);
8745
9250
  if (dep.installCommand) {
8746
- console.log(` \x1B[33mInstall: ${dep.installCommand}\x1B[0m`);
9251
+ console.log(` ${c2.yellow}Install: ${dep.installCommand}${c2.reset}`);
8747
9252
  }
8748
9253
  } else {
8749
- console.log(` \x1B[33m○\x1B[0m ${dep.name} \x1B[90m(optional)\x1B[0m`);
8750
- console.log(` \x1B[90m${info2}\x1B[0m`);
9254
+ console.log(` ${c2.yellow}○${c2.reset} ${dep.name} ${c2.dim}(recommended)${c2.reset}`);
9255
+ console.log(` ${c2.dim}${info2[dep.name] || ""}${c2.reset}`);
8751
9256
  if (dep.installCommand) {
8752
- console.log(` \x1B[90mInstall later: ${dep.installCommand}\x1B[0m`);
9257
+ console.log(` ${c2.dim}Install: ${dep.installCommand}${c2.reset}`);
8753
9258
  }
8754
9259
  }
8755
9260
  }
@@ -8758,19 +9263,22 @@ async function initDatacore(options = {}) {
8758
9263
  if (doctor.status === "missing_required") {
8759
9264
  const missing = doctor.dependencies.filter((d) => d.required && !d.installed);
8760
9265
  for (const dep of missing) {
8761
- result.errors.push(`Missing required dependency: ${dep.name}`);
8762
- if (dep.installCommand) {
8763
- result.errors.push(` Install with: ${dep.installCommand}`);
8764
- }
9266
+ result.errors.push(`Missing required: ${dep.name}`);
9267
+ }
9268
+ if (isTTY) {
9269
+ console.log(` ${c2.red}${c2.bold}Cannot continue - install required dependencies first.${c2.reset}`);
9270
+ console.log();
8765
9271
  }
8766
9272
  op.failStep("check_dependencies", "Missing required dependencies");
8767
9273
  op.fail("Missing required dependencies");
8768
9274
  return result;
8769
9275
  }
8770
- if (doctor.status === "missing_recommended") {
8771
- const missing = doctor.dependencies.filter((d) => !d.required && !d.installed);
8772
- for (const dep of missing) {
8773
- result.warnings.push(`Optional: ${dep.name} - install for full functionality`);
9276
+ if (interactive && !gitStatus.configured) {
9277
+ const proceed = await confirm("Git is not configured. Continue anyway?", false);
9278
+ if (!proceed) {
9279
+ result.errors.push("User cancelled: git not configured");
9280
+ op.fail("User cancelled");
9281
+ return result;
8774
9282
  }
8775
9283
  }
8776
9284
  }
@@ -8778,51 +9286,51 @@ async function initDatacore(options = {}) {
8778
9286
  op.addStep("create_data_dir");
8779
9287
  op.startStep("create_data_dir");
8780
9288
  if (isTTY) {
8781
- section("Setting Up ~/Data");
8782
- console.log(" \x1B[90mThis is your central knowledge directory. Everything lives here.\x1B[0m");
9289
+ section("Step 2: Creating ~/Data");
9290
+ console.log(` ${c2.dim}Your central knowledge directory. Everything lives here.${c2.reset}`);
8783
9291
  console.log();
8784
9292
  }
8785
- if (!existsSync6(DATA_DIR4)) {
8786
- mkdirSync4(DATA_DIR4, { recursive: true });
8787
- result.created.push(DATA_DIR4);
9293
+ if (!existsSync7(DATA_DIR5)) {
9294
+ mkdirSync4(DATA_DIR5, { recursive: true });
9295
+ result.created.push(DATA_DIR5);
9296
+ if (isTTY)
9297
+ console.log(` ${c2.green}✓${c2.reset} Created ${DATA_DIR5}`);
9298
+ } else {
8788
9299
  if (isTTY)
8789
- console.log(` \x1B[32m✓\x1B[0m Created ${DATA_DIR4}`);
8790
- } else if (isTTY) {
8791
- console.log(` \x1B[32m✓\x1B[0m Found existing ${DATA_DIR4}`);
9300
+ console.log(` ${c2.green}✓${c2.reset} Found ${DATA_DIR5}`);
8792
9301
  }
9302
+ if (isTTY)
9303
+ console.log();
8793
9304
  op.completeStep("create_data_dir");
8794
9305
  op.addStep("create_datacore_dir");
8795
9306
  op.startStep("create_datacore_dir");
8796
9307
  if (isTTY) {
8797
- console.log();
8798
- section("Creating .datacore");
8799
- console.log(" \x1B[90mSystem configuration, agents, and modules live here.\x1B[0m");
9308
+ section("Step 3: Creating .datacore");
9309
+ console.log(` ${c2.dim}System configuration, agents, commands, and modules.${c2.reset}`);
8800
9310
  console.log();
8801
9311
  }
8802
- if (!existsSync6(DATACORE_DIR)) {
9312
+ if (!existsSync7(DATACORE_DIR)) {
8803
9313
  const dirs = [
8804
- { path: "", desc: "Core configuration" },
8805
- { path: "commands", desc: "Slash commands (e.g., /today, /sync)" },
9314
+ { path: "", desc: "" },
9315
+ { path: "commands", desc: "Slash commands (/today, /sync, etc.)" },
8806
9316
  { path: "agents", desc: "AI agents for task automation" },
8807
- { path: "modules", desc: "Optional extensions (CRM, meetings, etc.)" },
9317
+ { path: "modules", desc: "Optional extensions" },
8808
9318
  { path: "specs", desc: "System documentation" },
8809
9319
  { path: "lib", desc: "Shared utilities" },
8810
- { path: "env", desc: "Secrets and API keys (gitignored)" },
8811
- { path: "state", desc: "Runtime state (gitignored)" },
8812
- { path: "registry", desc: "Agent and command discovery" }
9320
+ { path: "env", desc: "API keys and secrets" },
9321
+ { path: "state", desc: "Runtime state" },
9322
+ { path: "registry", desc: "Agent/command discovery" }
8813
9323
  ];
8814
9324
  for (const { path: dir, desc } of dirs) {
8815
- const path = join6(DATACORE_DIR, dir);
8816
- if (!existsSync6(path)) {
8817
- mkdirSync4(path, { recursive: true });
8818
- result.created.push(path);
8819
- if (isTTY && dir) {
8820
- console.log(` \x1B[32m✓\x1B[0m ${dir}/ \x1B[90m- ${desc}\x1B[0m`);
8821
- }
9325
+ const path = join7(DATACORE_DIR, dir);
9326
+ mkdirSync4(path, { recursive: true });
9327
+ result.created.push(path);
9328
+ if (isTTY && dir) {
9329
+ console.log(` ${c2.green}✓${c2.reset} ${dir}/ ${c2.dim}- ${desc}${c2.reset}`);
8822
9330
  }
8823
9331
  }
8824
- writeFileSync4(join6(DATACORE_DIR, "settings.yaml"), `# Datacore Settings
8825
- # Override in settings.local.yaml
9332
+ writeFileSync4(join7(DATACORE_DIR, "settings.yaml"), `# Datacore Settings
9333
+ # Override in settings.local.yaml (gitignored)
8826
9334
 
8827
9335
  editor:
8828
9336
  open_markdown_on_generate: true
@@ -8839,95 +9347,167 @@ nightshift:
8839
9347
  server: ""
8840
9348
  auto_trigger: false
8841
9349
  `);
8842
- result.created.push(join6(DATACORE_DIR, "settings.yaml"));
8843
- writeFileSync4(join6(DATACORE_DIR, "registry", "agents.yaml"), `# Agent Registry
8844
- # Agents are discovered from .datacore/agents/ and module agents/
8845
-
9350
+ result.created.push(join7(DATACORE_DIR, "settings.yaml"));
9351
+ writeFileSync4(join7(DATACORE_DIR, "registry", "agents.yaml"), `# Agent Registry
8846
9352
  agents: []
8847
9353
  `);
8848
- result.created.push(join6(DATACORE_DIR, "registry", "agents.yaml"));
8849
- writeFileSync4(join6(DATACORE_DIR, "registry", "commands.yaml"), `# Command Registry
8850
- # Commands are discovered from .datacore/commands/ and module commands/
8851
-
9354
+ writeFileSync4(join7(DATACORE_DIR, "registry", "commands.yaml"), `# Command Registry
8852
9355
  commands: []
8853
9356
  `);
8854
- result.created.push(join6(DATACORE_DIR, "registry", "commands.yaml"));
8855
9357
  if (isTTY) {
8856
9358
  console.log();
8857
- console.log(` \x1B[32m✓\x1B[0m Created settings.yaml`);
8858
- console.log(" \x1B[90mCustomize in settings.local.yaml (gitignored)\x1B[0m");
9359
+ console.log(` ${c2.green}✓${c2.reset} Created settings.yaml`);
9360
+ console.log(` ${c2.dim}Customize in settings.local.yaml${c2.reset}`);
8859
9361
  }
8860
- } else if (isTTY) {
8861
- console.log(` \x1B[32m✓\x1B[0m Found existing .datacore/`);
9362
+ } else {
9363
+ if (isTTY)
9364
+ console.log(` ${c2.green}✓${c2.reset} Found existing .datacore/`);
8862
9365
  }
9366
+ if (isTTY)
9367
+ console.log();
8863
9368
  op.completeStep("create_datacore_dir");
8864
9369
  op.addStep("create_personal_space");
8865
9370
  op.startStep("create_personal_space");
8866
9371
  if (isTTY) {
8867
- console.log();
8868
- section("Creating Personal Space");
8869
- console.log(" \x1B[90mSpaces are separate knowledge areas (personal, work, projects).\x1B[0m");
8870
- console.log(" \x1B[90mEach space has its own GTD inbox, notes, and journals.\x1B[0m");
9372
+ section("Step 4: Creating Personal Space");
9373
+ console.log(` ${c2.dim}Your personal GTD system and knowledge base.${c2.reset}`);
8871
9374
  console.log();
8872
9375
  }
8873
- const spaces = listSpaces();
8874
- if (spaces.length === 0) {
8875
- try {
8876
- const space = createSpace("personal", "personal");
8877
- result.created.push(space.path);
8878
- if (isTTY) {
8879
- console.log(` \x1B[32m✓\x1B[0m Created 0-personal/`);
8880
- console.log(" \x1B[90morg/inbox.org - Capture tasks here\x1B[0m");
8881
- console.log(" \x1B[90mnotes/ - Your knowledge base\x1B[0m");
8882
- console.log(" \x1B[90mjournal/ - Daily entries\x1B[0m");
8883
- }
8884
- } catch (err) {
8885
- result.warnings.push(`Could not create personal space: ${err.message}`);
9376
+ const existingSpaces = listSpaces();
9377
+ const hasPersonal = existingSpaces.some((s) => s.number === 0);
9378
+ if (!hasPersonal) {
9379
+ const space = createSpace("personal", "personal");
9380
+ result.created.push(space.path);
9381
+ result.spacesCreated.push(space.name);
9382
+ if (isTTY) {
9383
+ console.log(` ${c2.green}✓${c2.reset} Created 0-personal/`);
9384
+ console.log();
9385
+ console.log(` ${c2.bold}GTD System (org/):${c2.reset}`);
9386
+ console.log(` ${c2.cyan}inbox.org${c2.reset} ${c2.dim}- Capture everything here${c2.reset}`);
9387
+ console.log(` ${c2.cyan}next_actions.org${c2.reset} ${c2.dim}- Tasks by focus area${c2.reset}`);
9388
+ console.log(` ${c2.cyan}nightshift.org${c2.reset} ${c2.dim}- AI task queue (overnight)${c2.reset}`);
9389
+ console.log(` ${c2.cyan}habits.org${c2.reset} ${c2.dim}- Daily/weekly routines${c2.reset}`);
9390
+ console.log(` ${c2.cyan}someday.org${c2.reset} ${c2.dim}- Future ideas${c2.reset}`);
9391
+ console.log();
9392
+ console.log(` ${c2.bold}Knowledge:${c2.reset}`);
9393
+ console.log(` ${c2.cyan}notes/${c2.reset} ${c2.dim}- Personal wiki (Obsidian)${c2.reset}`);
9394
+ console.log(` ${c2.cyan}3-knowledge/${c2.reset} ${c2.dim}- Zettelkasten structure${c2.reset}`);
9395
+ console.log();
9396
+ console.log(` ${c2.bold}AI Delegation:${c2.reset}`);
9397
+ console.log(` ${c2.dim}Tag tasks with :AI: to delegate:${c2.reset}`);
9398
+ console.log(` ${c2.dim}:AI:research: :AI:content: :AI:data: :AI:pm:${c2.reset}`);
8886
9399
  }
8887
- } else if (isTTY) {
8888
- console.log(` \x1B[32m✓\x1B[0m Found ${spaces.length} existing space(s):`);
8889
- for (const space of spaces) {
8890
- console.log(` \x1B[90m${space.name}/\x1B[0m`);
9400
+ } else {
9401
+ if (isTTY) {
9402
+ console.log(` ${c2.green}✓${c2.reset} Found existing personal space`);
8891
9403
  }
8892
9404
  }
9405
+ if (isTTY)
9406
+ console.log();
8893
9407
  op.completeStep("create_personal_space");
9408
+ if (interactive) {
9409
+ section("Step 5: Additional Spaces");
9410
+ console.log(` ${c2.dim}Spaces separate different areas of your life (work, projects, teams).${c2.reset}`);
9411
+ console.log(` ${c2.dim}Each space is a separate git repo with its own GTD system.${c2.reset}`);
9412
+ console.log();
9413
+ const wantMoreSpaces = await confirm("Would you like to create additional spaces?", false);
9414
+ if (wantMoreSpaces) {
9415
+ let creating = true;
9416
+ while (creating) {
9417
+ const name = await prompt('Space name (e.g., "work", "acme-corp")');
9418
+ if (!name) {
9419
+ creating = false;
9420
+ continue;
9421
+ }
9422
+ try {
9423
+ const space = createSpace(name, "team");
9424
+ result.created.push(space.path);
9425
+ result.spacesCreated.push(space.name);
9426
+ console.log(` ${c2.green}✓${c2.reset} Created ${space.name}/`);
9427
+ } catch (err) {
9428
+ console.log(` ${c2.red}✗${c2.reset} ${err.message}`);
9429
+ }
9430
+ creating = await confirm("Create another space?", false);
9431
+ }
9432
+ }
9433
+ console.log();
9434
+ }
9435
+ if (interactive) {
9436
+ section("Step 6: Install Modules");
9437
+ console.log(` ${c2.dim}Modules add features like overnight AI processing, CRM, and more.${c2.reset}`);
9438
+ console.log();
9439
+ const available = getAvailableModules();
9440
+ if (available.length > 0) {
9441
+ const wantModules = await confirm("Would you like to install modules?", true);
9442
+ if (wantModules) {
9443
+ console.log();
9444
+ console.log(" Available modules:");
9445
+ console.log();
9446
+ for (let i = 0;i < available.length; i++) {
9447
+ const mod = available[i];
9448
+ console.log(` ${c2.cyan}${i + 1}${c2.reset}) ${c2.bold}${mod.name}${c2.reset} - ${mod.description}`);
9449
+ for (const feature of mod.features) {
9450
+ console.log(` ${c2.dim}• ${feature}${c2.reset}`);
9451
+ }
9452
+ console.log();
9453
+ }
9454
+ const choices = await prompt('Enter numbers to install (comma-separated, or "all", or "none")');
9455
+ let toInstall = [];
9456
+ if (choices.toLowerCase() === "all") {
9457
+ toInstall = available.map((m) => m.name);
9458
+ } else if (choices && choices.toLowerCase() !== "none") {
9459
+ const nums = choices.split(",").map((s) => parseInt(s.trim(), 10));
9460
+ toInstall = nums.filter((n) => n >= 1 && n <= available.length).map((n) => available[n - 1].name);
9461
+ }
9462
+ for (const modName of toInstall) {
9463
+ const mod = available.find((m) => m.name === modName);
9464
+ if (!mod)
9465
+ continue;
9466
+ const spinner = new Spinner(`Installing ${modName}...`);
9467
+ spinner.start();
9468
+ try {
9469
+ await sleep(100);
9470
+ installModule(mod.repo);
9471
+ spinner.succeed(`Installed ${modName}`);
9472
+ result.modulesInstalled.push(modName);
9473
+ } catch (err) {
9474
+ spinner.fail(`Failed to install ${modName}: ${err.message}`);
9475
+ result.warnings.push(`Failed to install ${modName}`);
9476
+ }
9477
+ }
9478
+ }
9479
+ } else {
9480
+ console.log(` ${c2.dim}No additional modules available to install.${c2.reset}`);
9481
+ }
9482
+ console.log();
9483
+ }
8894
9484
  op.addStep("create_claude_symlink");
8895
9485
  op.startStep("create_claude_symlink");
8896
9486
  if (isTTY) {
8897
- console.log();
8898
- section("Linking Claude Code");
8899
- console.log(" \x1B[90mClaude Code looks for .claude/ to find project context.\x1B[0m");
8900
- console.log(" \x1B[90mThis symlink connects it to your Datacore configuration.\x1B[0m");
9487
+ section("Step 7: Claude Code Integration");
9488
+ console.log(` ${c2.dim}Connecting Datacore to Claude Code AI assistant.${c2.reset}`);
8901
9489
  console.log();
8902
9490
  }
8903
- const claudeDir = join6(DATA_DIR4, ".claude");
8904
- if (!existsSync6(claudeDir)) {
9491
+ const claudeDir = join7(DATA_DIR5, ".claude");
9492
+ if (!existsSync7(claudeDir)) {
8905
9493
  try {
8906
9494
  symlinkSync(DATACORE_DIR, claudeDir);
8907
9495
  result.created.push(claudeDir);
8908
9496
  if (isTTY)
8909
- console.log(` \x1B[32m✓\x1B[0m Created .claude -> .datacore symlink`);
9497
+ console.log(` ${c2.green}✓${c2.reset} Created .claude -> .datacore symlink`);
8910
9498
  } catch {
8911
9499
  result.warnings.push("Could not create .claude symlink");
8912
9500
  if (isTTY)
8913
- console.log(` \x1B[33m○\x1B[0m Could not create symlink (run manually if needed)`);
9501
+ console.log(` ${c2.yellow}○${c2.reset} Could not create symlink`);
8914
9502
  }
8915
- } else if (isTTY) {
8916
- console.log(` \x1B[32m✓\x1B[0m Found existing .claude/`);
8917
- }
8918
- op.completeStep("create_claude_symlink");
8919
- op.addStep("create_claude_md");
8920
- op.startStep("create_claude_md");
8921
- if (isTTY) {
8922
- console.log();
8923
- section("Creating CLAUDE.md");
8924
- console.log(" \x1B[90mThis file tells Claude Code about your Datacore system.\x1B[0m");
8925
- console.log(" \x1B[90mIt auto-loads when you run `claude` in ~/Data.\x1B[0m");
8926
- console.log();
9503
+ } else {
9504
+ if (isTTY)
9505
+ console.log(` ${c2.green}✓${c2.reset} Found existing .claude/`);
8927
9506
  }
8928
- const claudeMd = join6(DATA_DIR4, "CLAUDE.md");
8929
- const claudeBaseMd = join6(DATA_DIR4, "CLAUDE.base.md");
8930
- if (!existsSync6(claudeMd) && !existsSync6(claudeBaseMd)) {
9507
+ const claudeMd = join7(DATA_DIR5, "CLAUDE.md");
9508
+ const claudeBaseMd = join7(DATA_DIR5, "CLAUDE.base.md");
9509
+ if (!existsSync7(claudeMd) && !existsSync7(claudeBaseMd)) {
9510
+ const allSpaces = listSpaces();
8931
9511
  writeFileSync4(claudeBaseMd, `# Datacore
8932
9512
 
8933
9513
  AI-powered second brain built on GTD methodology.
@@ -8938,16 +9518,24 @@ AI-powered second brain built on GTD methodology.
8938
9518
  cd ~/Data && claude
8939
9519
  \`\`\`
8940
9520
 
9521
+ ## Daily Workflow
9522
+
9523
+ 1. **Morning**: Run \`/today\` for your daily briefing
9524
+ 2. **Capture**: Add tasks to \`0-personal/org/inbox.org\`
9525
+ 3. **Process**: Clear inbox, organize by context
9526
+ 4. **Work**: Use \`:AI:\` tags to delegate tasks
9527
+ 5. **Evening**: Run \`/tomorrow\` for wrap-up
9528
+
8941
9529
  ## Commands
8942
9530
 
8943
- - \`datacore today\` - Daily briefing
8944
- - \`datacore tomorrow\` - End-of-day wrap-up
8945
- - \`datacore sync\` - Sync all repos
9531
+ - \`/today\` - Daily briefing with priorities
9532
+ - \`/tomorrow\` - End-of-day wrap-up
9533
+ - \`/sync\` - Sync all repos
8946
9534
  - \`datacore doctor\` - Check system health
8947
9535
 
8948
9536
  ## Spaces
8949
9537
 
8950
- ${listSpaces().map((s) => `- ${s.name}`).join(`
9538
+ ${allSpaces.map((s) => `- ${s.name}`).join(`
8951
9539
  `) || "- 0-personal"}
8952
9540
 
8953
9541
  ## Documentation
@@ -8956,30 +9544,47 @@ See .datacore/specs/ for detailed documentation.
8956
9544
  `);
8957
9545
  result.created.push(claudeBaseMd);
8958
9546
  if (isTTY)
8959
- console.log(` \x1B[32m✓\x1B[0m Created CLAUDE.base.md`);
8960
- } else if (isTTY) {
8961
- console.log(` \x1B[32m✓\x1B[0m Found existing CLAUDE.md`);
9547
+ console.log(` ${c2.green}✓${c2.reset} Created CLAUDE.base.md`);
9548
+ } else {
9549
+ if (isTTY)
9550
+ console.log(` ${c2.green}✓${c2.reset} Found existing CLAUDE.md`);
8962
9551
  }
8963
- op.completeStep("create_claude_md");
9552
+ if (isTTY)
9553
+ console.log();
9554
+ op.completeStep("create_claude_symlink");
8964
9555
  result.success = true;
8965
9556
  result.nextSteps = [
8966
- "Run `datacore doctor` to verify your setup",
8967
- "Start working: `cd ~/Data && claude`"
9557
+ "cd ~/Data && claude",
9558
+ "Add tasks to 0-personal/org/inbox.org",
9559
+ "Run /today for your first daily briefing"
8968
9560
  ];
8969
9561
  if (isTTY) {
8970
- console.log();
8971
9562
  console.log(INIT_COMPLETE);
8972
9563
  console.log();
8973
- console.log(" \x1B[1mNext steps:\x1B[0m");
9564
+ console.log(` ${c2.bold}Setup Complete!${c2.reset}`);
9565
+ console.log();
9566
+ if (result.spacesCreated.length > 0) {
9567
+ console.log(` ${c2.green}Spaces created:${c2.reset} ${result.spacesCreated.join(", ")}`);
9568
+ }
9569
+ if (result.modulesInstalled.length > 0) {
9570
+ console.log(` ${c2.green}Modules installed:${c2.reset} ${result.modulesInstalled.join(", ")}`);
9571
+ }
9572
+ if (result.warnings.length > 0) {
9573
+ console.log(` ${c2.yellow}Warnings:${c2.reset} ${result.warnings.length}`);
9574
+ }
9575
+ console.log();
9576
+ console.log(` ${c2.bold}Get Started:${c2.reset}`);
8974
9577
  console.log();
8975
- console.log(" 1. \x1B[36mcd ~/Data && claude\x1B[0m");
8976
- console.log(" \x1B[90mStart using your second brain with AI assistance\x1B[0m");
9578
+ console.log(` ${c2.cyan}1.${c2.reset} cd ~/Data && claude`);
9579
+ console.log(` ${c2.dim}Start Claude Code in your Datacore directory${c2.reset}`);
8977
9580
  console.log();
8978
- console.log(" 2. \x1B[36mdatacore doctor\x1B[0m");
8979
- console.log(" \x1B[90mVerify everything is set up correctly\x1B[0m");
9581
+ console.log(` ${c2.cyan}2.${c2.reset} Type ${c2.cyan}/today${c2.reset}`);
9582
+ console.log(` ${c2.dim}Get your first daily briefing${c2.reset}`);
8980
9583
  console.log();
8981
- console.log(" 3. Add tasks to \x1B[36m0-personal/org/inbox.org\x1B[0m");
8982
- console.log(" \x1B[90mYour GTD capture inbox - process daily\x1B[0m");
9584
+ console.log(` ${c2.cyan}3.${c2.reset} Add tasks to ${c2.cyan}0-personal/org/inbox.org${c2.reset}`);
9585
+ console.log(` ${c2.dim}Your GTD capture inbox${c2.reset}`);
9586
+ console.log();
9587
+ console.log(` ${c2.dim}Run 'datacore doctor' anytime to check system health.${c2.reset}`);
8983
9588
  console.log();
8984
9589
  }
8985
9590
  op.complete();
@@ -8990,150 +9595,14 @@ See .datacore/specs/ for detailed documentation.
8990
9595
  return result;
8991
9596
  }
8992
9597
 
8993
- // src/lib/module.ts
8994
- import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync4, rmSync } from "fs";
8995
- import { join as join7, basename as basename3 } from "path";
8996
- import { execSync as execSync4 } from "child_process";
8997
- var DATA_DIR5 = join7(process.env.HOME || "~", "Data");
8998
- var MODULES_DIR = join7(DATA_DIR5, ".datacore", "modules");
8999
- function listModules() {
9000
- if (!existsSync7(MODULES_DIR)) {
9001
- return [];
9002
- }
9003
- const entries = readdirSync2(MODULES_DIR, { withFileTypes: true });
9004
- const modules = [];
9005
- for (const entry of entries) {
9006
- if (!entry.isDirectory())
9007
- continue;
9008
- if (entry.name.startsWith("."))
9009
- continue;
9010
- const modulePath = join7(MODULES_DIR, entry.name);
9011
- const info2 = getModuleInfo(modulePath);
9012
- if (info2) {
9013
- modules.push(info2);
9014
- }
9015
- }
9016
- return modules;
9017
- }
9018
- function getModuleInfo(modulePath) {
9019
- const name = basename3(modulePath);
9020
- const yamlPath = join7(modulePath, "module.yaml");
9021
- const ymlPath = join7(modulePath, "module.yml");
9022
- const configPath = existsSync7(yamlPath) ? yamlPath : existsSync7(ymlPath) ? ymlPath : null;
9023
- let version;
9024
- let description;
9025
- if (configPath) {
9026
- try {
9027
- const { parse: parse2 } = require_dist();
9028
- const content = readFileSync4(configPath, "utf-8");
9029
- const config = parse2(content);
9030
- version = config.version;
9031
- description = config.description;
9032
- } catch {}
9033
- }
9034
- const agentsDir = join7(modulePath, "agents");
9035
- const agents = [];
9036
- if (existsSync7(agentsDir)) {
9037
- const agentFiles = readdirSync2(agentsDir);
9038
- for (const file of agentFiles) {
9039
- if (file.endsWith(".md")) {
9040
- agents.push(file.replace(".md", ""));
9041
- }
9042
- }
9043
- }
9044
- const commandsDir = join7(modulePath, "commands");
9045
- const commands = [];
9046
- if (existsSync7(commandsDir)) {
9047
- const cmdFiles = readdirSync2(commandsDir);
9048
- for (const file of cmdFiles) {
9049
- if (file.endsWith(".md")) {
9050
- commands.push(file.replace(".md", ""));
9051
- }
9052
- }
9053
- }
9054
- return {
9055
- name,
9056
- path: modulePath,
9057
- version,
9058
- description,
9059
- agents,
9060
- commands
9061
- };
9062
- }
9063
- function installModule(source) {
9064
- if (!existsSync7(MODULES_DIR)) {
9065
- const { mkdirSync: mkdirSync5 } = __require("fs");
9066
- mkdirSync5(MODULES_DIR, { recursive: true });
9067
- }
9068
- let name;
9069
- let isGit = false;
9070
- if (source.includes("github.com") || source.startsWith("git@") || source.endsWith(".git")) {
9071
- isGit = true;
9072
- const match = source.match(/([^/]+?)(?:\.git)?$/);
9073
- name = match?.[1] ?? source.split("/").pop() ?? "unknown";
9074
- name = name.replace(/^module-/, "");
9075
- } else if (source.startsWith("@")) {
9076
- name = source.split("/").pop()?.replace(/^datacore-/, "") ?? "unknown";
9077
- } else {
9078
- name = source.replace(/^datacore-/, "").replace(/^module-/, "");
9079
- }
9080
- const modulePath = join7(MODULES_DIR, name);
9081
- if (existsSync7(modulePath)) {
9082
- throw new Error(`Module already installed: ${name}`);
9083
- }
9084
- if (isGit) {
9085
- execSync4(`git clone ${source} "${modulePath}"`, { stdio: "pipe" });
9086
- } else {
9087
- const gitUrl = `https://github.com/datacore/module-${name}.git`;
9088
- try {
9089
- execSync4(`git clone ${gitUrl} "${modulePath}"`, { stdio: "pipe" });
9090
- } catch {
9091
- throw new Error(`Could not install module: ${source}`);
9092
- }
9093
- }
9094
- const info2 = getModuleInfo(modulePath);
9095
- if (!info2) {
9096
- rmSync(modulePath, { recursive: true, force: true });
9097
- throw new Error("Invalid module: missing module.yaml");
9098
- }
9099
- return info2;
9100
- }
9101
- function updateModules(name) {
9102
- const modules = listModules();
9103
- const results = [];
9104
- const toUpdate = name ? modules.filter((m) => m.name === name) : modules;
9105
- for (const mod of toUpdate) {
9106
- try {
9107
- const gitDir = join7(mod.path, ".git");
9108
- if (existsSync7(gitDir)) {
9109
- execSync4("git pull", { cwd: mod.path, stdio: "pipe" });
9110
- results.push({ name: mod.name, updated: true });
9111
- } else {
9112
- results.push({ name: mod.name, updated: false, error: "Not a git repository" });
9113
- }
9114
- } catch (err) {
9115
- results.push({ name: mod.name, updated: false, error: err.message });
9116
- }
9117
- }
9118
- return results;
9119
- }
9120
- function removeModule(name) {
9121
- const modulePath = join7(MODULES_DIR, name);
9122
- if (!existsSync7(modulePath)) {
9123
- return false;
9124
- }
9125
- rmSync(modulePath, { recursive: true, force: true });
9126
- return true;
9127
- }
9128
-
9129
9598
  // src/lib/snapshot.ts
9130
9599
  var import_yaml2 = __toESM(require_dist(), 1);
9131
- import { existsSync as existsSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
9600
+ import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
9132
9601
  import { execSync as execSync5 } from "child_process";
9133
9602
  import { join as join8 } from "path";
9134
9603
  var DATA_DIR6 = join8(process.env.HOME || "~", "Data");
9135
9604
  var LOCK_FILE = join8(DATA_DIR6, "datacore.lock.yaml");
9136
- var CLI_VERSION = "1.0.4";
9605
+ var CLI_VERSION = "1.0.6";
9137
9606
  function getGitInfo(path) {
9138
9607
  if (!existsSync8(join8(path, ".git"))) {
9139
9608
  return {};
@@ -9199,7 +9668,7 @@ function createSnapshot(options = {}) {
9199
9668
  const settingsPath = join8(DATA_DIR6, ".datacore", "settings.yaml");
9200
9669
  if (existsSync8(settingsPath)) {
9201
9670
  try {
9202
- const content = readFileSync5(settingsPath, "utf-8");
9671
+ const content = readFileSync4(settingsPath, "utf-8");
9203
9672
  snapshot.settings = import_yaml2.parse(content);
9204
9673
  } catch {}
9205
9674
  }
@@ -9220,7 +9689,7 @@ function loadSnapshot(path) {
9220
9689
  return null;
9221
9690
  }
9222
9691
  try {
9223
- const content = readFileSync5(lockPath, "utf-8");
9692
+ const content = readFileSync4(lockPath, "utf-8");
9224
9693
  return import_yaml2.parse(content);
9225
9694
  } catch {
9226
9695
  return null;
@@ -9352,7 +9821,7 @@ function restoreFromSnapshot(snapshot, options = {}) {
9352
9821
  }
9353
9822
 
9354
9823
  // src/index.ts
9355
- var VERSION = "1.0.4";
9824
+ var VERSION = "1.0.6";
9356
9825
  var args = process.argv.slice(2);
9357
9826
  var parsed = parseArgs(args);
9358
9827
  async function handleMeta(command, cmdArgs, flags, format) {
@@ -9400,8 +9869,8 @@ async function handleMeta(command, cmdArgs, flags, format) {
9400
9869
  }
9401
9870
  console.log();
9402
9871
  console.log("Next steps:");
9403
- for (const step2 of result.nextSteps) {
9404
- console.log(` → ${step2}`);
9872
+ for (const step of result.nextSteps) {
9873
+ console.log(` → ${step}`);
9405
9874
  }
9406
9875
  } else {
9407
9876
  error("Initialization failed");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datacore-one/cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "CLI for setting up and managing Datacore installations",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",