@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.
- package/dist/index.js +770 -301
- 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
|
|
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",
|
|
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:
|
|
7110
|
+
const { readFileSync: readFileSync5 } = __require("fs");
|
|
7111
7111
|
const { parse: parse3 } = require_dist();
|
|
7112
|
-
const content =
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
8543
|
-
import { join as
|
|
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
|
|
8547
|
-
import { join as
|
|
8548
|
-
var STATE_DIR =
|
|
8549
|
-
var STATE_FILE =
|
|
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 (!
|
|
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 (!
|
|
8969
|
+
if (!existsSync6(STATE_FILE)) {
|
|
8558
8970
|
return { operations: [] };
|
|
8559
8971
|
}
|
|
8560
8972
|
try {
|
|
8561
|
-
const content =
|
|
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
|
|
8697
|
-
var DATACORE_DIR =
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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(`
|
|
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(`
|
|
8744
|
-
console.log(`
|
|
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(`
|
|
9251
|
+
console.log(` ${c2.yellow}Install: ${dep.installCommand}${c2.reset}`);
|
|
8747
9252
|
}
|
|
8748
9253
|
} else {
|
|
8749
|
-
console.log(`
|
|
8750
|
-
console.log(`
|
|
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(`
|
|
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
|
|
8762
|
-
|
|
8763
|
-
|
|
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 (
|
|
8771
|
-
const
|
|
8772
|
-
|
|
8773
|
-
result.
|
|
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("
|
|
8782
|
-
console.log(
|
|
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 (!
|
|
8786
|
-
mkdirSync4(
|
|
8787
|
-
result.created.push(
|
|
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(`
|
|
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
|
-
|
|
8798
|
-
|
|
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 (!
|
|
9312
|
+
if (!existsSync7(DATACORE_DIR)) {
|
|
8803
9313
|
const dirs = [
|
|
8804
|
-
{ path: "", desc: "
|
|
8805
|
-
{ path: "commands", desc: "Slash commands (
|
|
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
|
|
9317
|
+
{ path: "modules", desc: "Optional extensions" },
|
|
8808
9318
|
{ path: "specs", desc: "System documentation" },
|
|
8809
9319
|
{ path: "lib", desc: "Shared utilities" },
|
|
8810
|
-
{ path: "env", desc: "
|
|
8811
|
-
{ path: "state", desc: "Runtime state
|
|
8812
|
-
{ path: "registry", desc: "Agent
|
|
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 =
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
|
|
8819
|
-
|
|
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(
|
|
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(
|
|
8843
|
-
writeFileSync4(
|
|
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
|
-
|
|
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(`
|
|
8858
|
-
console.log(
|
|
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
|
|
8861
|
-
|
|
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
|
-
|
|
8868
|
-
|
|
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
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
8882
|
-
|
|
8883
|
-
}
|
|
8884
|
-
|
|
8885
|
-
|
|
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
|
|
8888
|
-
|
|
8889
|
-
|
|
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
|
-
|
|
8898
|
-
|
|
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 =
|
|
8904
|
-
if (!
|
|
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(`
|
|
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(`
|
|
9501
|
+
console.log(` ${c2.yellow}○${c2.reset} Could not create symlink`);
|
|
8914
9502
|
}
|
|
8915
|
-
} else
|
|
8916
|
-
|
|
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 =
|
|
8929
|
-
const claudeBaseMd =
|
|
8930
|
-
if (!
|
|
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
|
-
-
|
|
8944
|
-
-
|
|
8945
|
-
-
|
|
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
|
-
${
|
|
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(`
|
|
8960
|
-
} else
|
|
8961
|
-
|
|
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
|
-
|
|
9552
|
+
if (isTTY)
|
|
9553
|
+
console.log();
|
|
9554
|
+
op.completeStep("create_claude_symlink");
|
|
8964
9555
|
result.success = true;
|
|
8965
9556
|
result.nextSteps = [
|
|
8966
|
-
"
|
|
8967
|
-
"
|
|
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(
|
|
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(
|
|
8976
|
-
console.log(
|
|
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(
|
|
8979
|
-
console.log(
|
|
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(
|
|
8982
|
-
console.log(
|
|
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
|
|
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.
|
|
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 =
|
|
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 =
|
|
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.
|
|
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
|
|
9404
|
-
console.log(` → ${
|
|
9872
|
+
for (const step of result.nextSteps) {
|
|
9873
|
+
console.log(` → ${step}`);
|
|
9405
9874
|
}
|
|
9406
9875
|
} else {
|
|
9407
9876
|
error("Initialization failed");
|