dodo-mcp 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -6
- package/dist/cli/dataRecovery.js +38 -0
- package/dist/cli/dataRecovery.js.map +1 -0
- package/dist/cli/deployment.js +61 -0
- package/dist/cli/deployment.js.map +1 -0
- package/dist/cli/main.js +35 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/config/globalConfig.js +3 -5
- package/dist/config/globalConfig.js.map +1 -1
- package/dist/errors.js +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/ipc/server.js +2 -0
- package/dist/ipc/server.js.map +1 -1
- package/dist/ipc/timeouts.js +5 -0
- package/dist/ipc/timeouts.js.map +1 -0
- package/dist/platform/privateFs.js +32 -3
- package/dist/platform/privateFs.js.map +1 -1
- package/dist/platform/windowsPrivateAcl.js +90 -0
- package/dist/platform/windowsPrivateAcl.js.map +1 -0
- package/dist/security/outboundAddress.js +20 -0
- package/dist/security/outboundAddress.js.map +1 -0
- package/dist/server/aiAdmin.js +5 -4
- package/dist/server/aiAdmin.js.map +1 -1
- package/dist/server/appServer.js +2 -5
- package/dist/server/appServer.js.map +1 -1
- package/dist/server/bootstrap.js +14 -0
- package/dist/server/bootstrap.js.map +1 -1
- package/dist/server/configUi/index.html +3 -0
- package/dist/server/configUi/ui/dataRecovery.js +90 -0
- package/dist/server/configUi/ui/deployment.js +111 -0
- package/dist/server/configUi/ui/recovery.js +167 -0
- package/dist/server/configUi/workbench.js +23 -7
- package/dist/server/installationRuntime.js +3 -1
- package/dist/server/installationRuntime.js.map +1 -1
- package/dist/server/instructions.js.map +1 -1
- package/dist/server/ipcDispatch.js +219 -0
- package/dist/server/ipcDispatch.js.map +1 -1
- package/dist/server/localConfig.js +1 -1
- package/dist/server/localConfig.js.map +1 -1
- package/dist/server/stdioServer.js +2 -5
- package/dist/server/stdioServer.js.map +1 -1
- package/dist/services/ai/network.js +1 -18
- package/dist/services/ai/network.js.map +1 -1
- package/dist/services/ai/subagents.js +5 -2
- package/dist/services/ai/subagents.js.map +1 -1
- package/dist/services/assistance/verification.js +43 -10
- package/dist/services/assistance/verification.js.map +1 -1
- package/dist/services/changes/applier.js +472 -297
- package/dist/services/changes/applier.js.map +1 -1
- package/dist/services/git/gitService.js +150 -34
- package/dist/services/git/gitService.js.map +1 -1
- package/dist/services/jobs/jobManager.js +59 -2
- package/dist/services/jobs/jobManager.js.map +1 -1
- package/dist/services/jobs/spool.js +9 -3
- package/dist/services/jobs/spool.js.map +1 -1
- package/dist/services/multimodal/mediaService.js +6 -6
- package/dist/services/multimodal/mediaService.js.map +1 -1
- package/dist/services/recovery/configKeys.js +115 -0
- package/dist/services/recovery/configKeys.js.map +1 -0
- package/dist/services/recovery/configVault.js +361 -0
- package/dist/services/recovery/configVault.js.map +1 -0
- package/dist/services/recovery/contracts.js +24 -0
- package/dist/services/recovery/contracts.js.map +1 -0
- package/dist/services/recovery/databaseAwareness.js +179 -0
- package/dist/services/recovery/databaseAwareness.js.map +1 -0
- package/dist/services/recovery/deploymentArchive.js +129 -0
- package/dist/services/recovery/deploymentArchive.js.map +1 -0
- package/dist/services/recovery/deploymentContracts.js +70 -0
- package/dist/services/recovery/deploymentContracts.js.map +1 -0
- package/dist/services/recovery/deploymentHealth.js +143 -0
- package/dist/services/recovery/deploymentHealth.js.map +1 -0
- package/dist/services/recovery/deploymentMaintenance.js +197 -0
- package/dist/services/recovery/deploymentMaintenance.js.map +1 -0
- package/dist/services/recovery/deploymentService.js +429 -0
- package/dist/services/recovery/deploymentService.js.map +1 -0
- package/dist/services/recovery/deploymentSource.js +36 -0
- package/dist/services/recovery/deploymentSource.js.map +1 -0
- package/dist/services/recovery/dockerDeployment.js +172 -0
- package/dist/services/recovery/dockerDeployment.js.map +1 -0
- package/dist/services/recovery/drift.js +178 -0
- package/dist/services/recovery/drift.js.map +1 -0
- package/dist/services/recovery/evidence.js +127 -0
- package/dist/services/recovery/evidence.js.map +1 -0
- package/dist/services/recovery/gitCopies.js +219 -0
- package/dist/services/recovery/gitCopies.js.map +1 -0
- package/dist/services/recovery/history.js +423 -0
- package/dist/services/recovery/history.js.map +1 -0
- package/dist/services/recovery/recoveryService.js +521 -0
- package/dist/services/recovery/recoveryService.js.map +1 -0
- package/dist/services/recovery/storage.js +344 -0
- package/dist/services/recovery/storage.js.map +1 -0
- package/dist/services/schedules/scheduleService.js +9 -10
- package/dist/services/schedules/scheduleService.js.map +1 -1
- package/dist/store/db.js +71 -0
- package/dist/store/db.js.map +1 -1
- package/dist/tools/catalog.js +4 -0
- package/dist/tools/catalog.js.map +1 -1
- package/dist/tools/changeTools.js +1 -1
- package/dist/tools/changeTools.js.map +1 -1
- package/dist/tools/context.js +23 -3
- package/dist/tools/context.js.map +1 -1
- package/dist/tools/deploymentTools.js +58 -0
- package/dist/tools/deploymentTools.js.map +1 -0
- package/dist/tools/directTools.js +9 -5
- package/dist/tools/directTools.js.map +1 -1
- package/dist/tools/gitTools.js +7 -2
- package/dist/tools/gitTools.js.map +1 -1
- package/dist/tools/jobTools.js +4 -4
- package/dist/tools/jobTools.js.map +1 -1
- package/dist/tools/projectTools.js +1 -0
- package/dist/tools/projectTools.js.map +1 -1
- package/dist/tools/recoveryTools.js +79 -0
- package/dist/tools/recoveryTools.js.map +1 -0
- package/dist/tools/runtimeTools.js +1 -1
- package/dist/tools/runtimeTools.js.map +1 -1
- package/dist/tools/surface.js +6 -1
- package/dist/tools/surface.js.map +1 -1
- package/dist/tunnel/credentials.js +1 -1
- package/dist/tunnel/credentials.js.map +1 -1
- package/docs/ARCHITECTURE.md +82 -2
- package/docs/CI.md +118 -0
- package/docs/COMPATIBILITY.md +7 -6
- package/docs/EVALUATION.md +17 -12
- package/docs/MANUAL_ACCEPTANCE.md +59 -2
- package/docs/RECOVERY.md +448 -0
- package/docs/RELEASE_1.3.0.md +64 -0
- package/docs/RELEASE_NOTES.md +23 -0
- package/docs/SECURITY.md +112 -0
- package/docs/TEST_REPORT.md +300 -5
- package/docs/adr/051-source-recovery-foundation.md +45 -0
- package/docs/adr/052-reviewed-source-restore.md +50 -0
- package/docs/adr/053-content-drift-and-private-git-recovery.md +29 -0
- package/docs/adr/054-verified-source-checkpoints.md +58 -0
- package/docs/adr/055-reviewed-docker-deployments.md +42 -0
- package/docs/adr/056-owner-data-recovery.md +47 -0
- package/docs/adr/README.md +7 -0
- package/native/private-state-windows.cs +105 -0
- package/package.json +6 -1
- package/schemas/global-config.schema.json +34 -0
- package/schemas/tools.compact.json +175 -15
- package/schemas/tools.hybrid.json +350 -16
- package/schemas/tools.json +4883 -816
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
- MCP ผ่าน HTTP ที่ `127.0.0.1:21730/mcp` พร้อม OAuth และ PKCE
|
|
8
8
|
- Local Config แบบ loopback ที่ `127.0.0.1:21731` และ Remote Config ชั่วคราวผ่าน tunnel เมื่อเจ้าของสั่ง `dodo --web`
|
|
9
9
|
- HTTP ใช้ Compact Tool Surface 20 tools เพื่อลดภาระการโหลด schema
|
|
10
|
-
- STDIO ใช้ Full Tool Surface; มี capability definitions ทั้งหมด
|
|
10
|
+
- STDIO ใช้ Full Tool Surface; มี capability definitions ทั้งหมด 158 รายการ แต่ค่าเริ่มต้นซ่อน Sub-agent 4 operations จาก MCP จึงเห็น 154 tools
|
|
11
11
|
- Hybrid Surface 49 tools สำหรับ client ที่รับ catalog ขนาดกลาง
|
|
12
12
|
- อ่าน ค้นหา สร้าง แก้ ย้าย ลบไฟล์ พร้อม expected hash, journal และ rollback
|
|
13
13
|
- รันคำสั่ง งานแบบขนาน jobs, Git, TypeScript/JavaScript intelligence, LSP และ task assistance
|
|
@@ -567,19 +567,23 @@ dodo desktop allow --app com.google.Chrome --mode control --persist --yes
|
|
|
567
567
|
|
|
568
568
|
## Development
|
|
569
569
|
|
|
570
|
-
Platform CI ใช้ dedicated self-hosted runners ที่เจ้าของควบคุม: Linux X64
|
|
571
|
-
|
|
570
|
+
Platform CI ใช้ dedicated self-hosted runners ที่เจ้าของควบคุม: Linux X64 และ
|
|
571
|
+
Windows X64 รัน native candidate gate บนเครื่อง runner โดยตรง ไม่ใช้ Docker ส่วน
|
|
572
572
|
macOS ยังรัน release gate บนเครื่องพัฒนา Workflow รับเฉพาะ push ที่ `main` และ manual
|
|
573
573
|
dispatch ไม่รัน pull request จากภายนอกบน self-hosted runner
|
|
574
574
|
|
|
575
|
-
รัน regression benchmark
|
|
575
|
+
รัน regression benchmark และ macOS candidate gate ได้ด้วย:
|
|
576
576
|
|
|
577
577
|
```bash
|
|
578
578
|
npm run bench
|
|
579
579
|
npm run release:gate
|
|
580
|
-
npm run test:linux:docker
|
|
581
580
|
```
|
|
582
581
|
|
|
582
|
+
สั่ง Linux/Windows CI ผ่าน GitHub Actions → `platform-gates` → Run workflow →
|
|
583
|
+
เลือก `all` หรือใช้ `gh workflow run platform-gates.yml --ref main -f platform=all`
|
|
584
|
+
Linux รันเมื่อสั่ง workflow; Windows รันทั้งเมื่อ push ไป main และเมื่อสั่ง workflow
|
|
585
|
+
อ่าน [การเตรียม runner และวิธีแก้ CI](docs/CI.md) ก่อนรันครั้งแรก
|
|
586
|
+
|
|
583
587
|
GitHub workflow รัน Node 22 และ 24 ทั้ง Linux/Windows โดยไม่ publish npm Windows จะ
|
|
584
588
|
ยังไม่ถูกประกาศเป็น supported platform จนกว่า automated native gate และ manual
|
|
585
589
|
Windows 11 acceptance จะผ่านตามเอกสาร
|
|
@@ -588,8 +592,9 @@ Release gate สร้างหลักฐาน non-secret ใน ignored `rel
|
|
|
588
592
|
exact-tarball ผ่าน STDIO Full กับ HTTP/OAuth Compact โดยไม่ publish npm ดูรายละเอียดที่
|
|
589
593
|
[DodoBench และ Release Gate](docs/EVALUATION.md)
|
|
590
594
|
|
|
591
|
-
เมื่อทั้งสอง report มาจาก Git revision และ `package-lock.json` เดียวกัน ให้รวมหลักฐาน
|
|
595
|
+
เมื่อทั้งสอง report มาจาก clean Git revision, source fingerprint และ `package-lock.json` เดียวกัน ให้รวมหลักฐาน
|
|
592
596
|
บน macOS ด้วย `node scripts/release-gate.mjs --release --platform-evidence /absolute/path/to/linux/gate-report.json`
|
|
597
|
+
Linux report ต้องมาจาก native GitHub Actions; หลักฐาน Docker เก่าไม่แทน CI รอบใหม่
|
|
593
598
|
คำสั่งนี้ไม่ publish package
|
|
594
599
|
|
|
595
600
|
```bash
|
|
@@ -602,3 +607,21 @@ npm pack
|
|
|
602
607
|
```
|
|
603
608
|
|
|
604
609
|
โปรเจกต์นี้ใช้ GitHub repository [arthittakun/dodo-mcp](https://github.com/arthittakun/dodo-mcp) และ package `dodo-mcp`
|
|
610
|
+
|
|
611
|
+
### Recovery — สำรองและกู้คืนงาน
|
|
612
|
+
|
|
613
|
+
โปรเจกต์ที่ลงทะเบียนเปิด source backup เป็นค่าเริ่มต้น ก่อนแก้ไฟล์หรือรันคำสั่ง
|
|
614
|
+
หน้า **Projects → Recovery** ใช้ตรวจประวัติ เปรียบเทียบ และยืนยันแผนกู้คืนได้จริง
|
|
615
|
+
หรือใช้ `dodo recovery --help` ผ่าน terminal สำเนาอยู่ใน private state แยกจาก Git
|
|
616
|
+
ของโปรเจกต์ และไม่ push ขึ้น GitHub อัตโนมัติ
|
|
617
|
+
|
|
618
|
+
- กู้คืน checkpoint หรือ session ที่เลือก พร้อม expected hashes, สำเนาก่อนกู้ และ receipt หลัง reconnect
|
|
619
|
+
- ตรวจไฟล์ที่ถูกแก้จากภายนอก และแยก `SAVED`, `VERIFIED`, `FAILED`, `INCONCLUSIVE`, `STALE` ให้เห็นตามหลักฐาน
|
|
620
|
+
- ตั้งชื่อ/pin จุดกู้คืน และตรวจ retention ก่อนล้าง โดยรักษางานที่ไม่เกี่ยวข้อง
|
|
621
|
+
- เพิ่ม Docker deployment target ได้โดยเจ้าของ: source ที่ตรวจแล้ว → image → health/stabilization → known-good พร้อม reviewed rollback
|
|
622
|
+
- ตรวจ SQLite migration compatibility แบบอ่านอย่างเดียว และสำรอง private config แบบเข้ารหัสเมื่อเจ้าของเปิดแยก
|
|
623
|
+
|
|
624
|
+
**Source restore ไม่ย้อนฐานข้อมูล, secrets, volumes หรือระบบภายนอก** การสำรอง config
|
|
625
|
+
ใช้กุญแจจาก OS credential store และไม่ส่งเนื้อหาให้ AI; ไม่มี generic database rollback
|
|
626
|
+
หรือการ restart service อัตโนมัติ ดู [คู่มือ Recovery](docs/RECOVERY.md),
|
|
627
|
+
[การเปลี่ยนแปลง 1.3.0](docs/RELEASE_1.3.0.md) และ [ผลตรวจรับจริง](docs/TEST_REPORT.md)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { DodoError } from '../errors.js';
|
|
3
|
+
export function registerDataRecoveryCommands(recovery, ipc) {
|
|
4
|
+
const database = recovery.command('database').description('owner-only read-only migration compatibility; never database rollback');
|
|
5
|
+
const print = (value) => console.log(JSON.stringify(value, null, 2));
|
|
6
|
+
database.command('targets').action(async () => print(await ipc('recovery.database.list')));
|
|
7
|
+
const review = (cmd) => cmd.requiredOption('--workspace <id>', 'current workspace ID').requiredOption('--epoch <epoch>', 'current epoch').option('--yes', 'confirm the exact owner operation', false);
|
|
8
|
+
const envelope = (opts, input) => {
|
|
9
|
+
if (!opts.yes)
|
|
10
|
+
throw new DodoError('INVALID_INPUT', 'review the owner operation and add --yes');
|
|
11
|
+
return { workspaceId: opts.workspace, workspaceEpoch: opts.epoch, confirm: true, input };
|
|
12
|
+
};
|
|
13
|
+
review(database.command('inspect <targetId>')).action(async (targetId, opts) => print(await ipc('recovery.database.inspect', envelope(opts, { targetId }))));
|
|
14
|
+
const jsonOperation = (group, operation, method) => review(group.command(operation).requiredOption('--file <path>', 'owner-reviewed bounded JSON; never secret values'))
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
const st = fs.lstatSync(opts.file);
|
|
17
|
+
if (!st.isFile() || st.isSymbolicLink() || st.nlink !== 1 || st.size > 128 * 1024)
|
|
18
|
+
throw new DodoError('INVALID_INPUT', 'expected a bounded regular JSON file');
|
|
19
|
+
let input;
|
|
20
|
+
try {
|
|
21
|
+
input = JSON.parse(fs.readFileSync(opts.file, 'utf8'));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new DodoError('INVALID_INPUT', 'invalid owner JSON');
|
|
25
|
+
}
|
|
26
|
+
print(await ipc(method, envelope(opts, input)));
|
|
27
|
+
});
|
|
28
|
+
for (const op of ['configure', 'bind', 'unbind'])
|
|
29
|
+
jsonOperation(database, op, 'recovery.database.' + op);
|
|
30
|
+
const vault = recovery.command('private-config').description('owner-only encrypted secret-file recovery; explicit opt-in and OS key store required');
|
|
31
|
+
vault.command('list').action(async () => print(await ipc('recovery.config.list')));
|
|
32
|
+
jsonOperation(vault, 'configure', 'recovery.config.configure');
|
|
33
|
+
review(vault.command('backup <targetId>')).action(async (targetId, opts) => print(await ipc('recovery.config.backup', envelope(opts, { targetId }))));
|
|
34
|
+
review(vault.command('preview <backupId>')).action(async (backupId, opts) => print(await ipc('recovery.config.preview', envelope(opts, { backupId }))));
|
|
35
|
+
review(vault.command('apply <planId>').requiredOption('--hash <hash>', 'exact reviewed plan hash')).action(async (planId, opts) => print(await ipc('recovery.config.apply', envelope(opts, { planId, planHash: opts.hash }))));
|
|
36
|
+
review(vault.command('rotate <targetId>').requiredOption('--revision <n>', 'current target revision', Number)).action(async (targetId, opts) => print(await ipc('recovery.config.rotate', envelope(opts, { targetId, expectedRevision: opts.revision }))));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=dataRecovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataRecovery.js","sourceRoot":"","sources":["../../src/cli/dataRecovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,4BAA4B,CAAC,QAAiB,EAAE,GAAsE;IACpI,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,CAAC,uEAAuE,CAAC,CAAC;IACnI,MAAM,KAAK,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9E,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC,CAAC;IAE3F,MAAM,MAAM,GAAG,CAAC,GAAY,EAAE,EAAE,CAAC,GAAG,CAAC,cAAc,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC,cAAc,CAAC,iBAAiB,EAAE,eAAe,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAC/M,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QAChD,IAAI,CAAC,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,0CAA0C,CAAC,CAAC;QAChG,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAC3F,CAAC,CAAC;IACF,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,2BAA2B,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7K,MAAM,aAAa,GAAG,CAAC,KAAc,EAAE,SAAiB,EAAE,MAAc,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,eAAe,EAAE,kDAAkD,CAAC,CAAC;SAC9L,MAAM,CAAC,KAAK,EAAE,IAA+B,EAAE,EAAE;QAChD,MAAM,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC,KAAK,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG,GAAG,GAAG,IAAI;YAAE,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,sCAAsC,CAAC,CAAC;QAChK,IAAI,KAAc,CAAC;QAAC,IAAI,CAAC;YAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,MAAM,IAAI,SAAS,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC;QAAC,CAAC;QACzJ,KAAK,CAAC,MAAM,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IACL,KAAK,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC;QAAE,aAAa,CAAC,QAAQ,EAAE,EAAE,EAAE,oBAAoB,GAAG,EAAE,CAAC,CAAC;IACzG,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,sFAAsF,CAAC,CAAC;IACrJ,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;IACnF,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,2BAA2B,CAAC,CAAC;IAC/D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,wBAAwB,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACtK,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAY,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,yBAAyB,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACxK,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,cAAc,CAAC,eAAe,EAAE,0BAA0B,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAA+B,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,uBAAuB,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAClQ,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,cAAc,CAAC,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,IAAmC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,wBAAwB,EAAE,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACpS,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import { DodoError } from '../errors.js';
|
|
3
|
+
/** Private owner IPC only; reviewed files are bounded JSON, never executable repository configuration. */
|
|
4
|
+
export function registerDeploymentCommands(program, ipc) {
|
|
5
|
+
const group = program.command('deployment').description('review registered Docker deployment targets and durable build/deploy outcomes');
|
|
6
|
+
const print = (value) => console.log(JSON.stringify(value, null, 2));
|
|
7
|
+
for (const op of ['targets', 'list'])
|
|
8
|
+
group.command(op).action(async () => print(await ipc(`deployment.${op}`)));
|
|
9
|
+
for (const op of ['inspect', 'compare'])
|
|
10
|
+
group.command(`${op} <deploymentId>`).action(async (deploymentId) => print(await ipc(`deployment.${op}`, { deploymentId })));
|
|
11
|
+
const reviewed = (cmd) => cmd.requiredOption('--workspace <id>', 'reviewed workspace ID')
|
|
12
|
+
.requiredOption('--epoch <epoch>', 'reviewed workspace epoch').option('--yes', 'confirm the exact reviewed operation', false);
|
|
13
|
+
const envelope = (opts, input) => {
|
|
14
|
+
if (!opts.yes)
|
|
15
|
+
throw new DodoError('INVALID_INPUT', 'review target/source and add --yes; Docker commands may affect resources outside the workspace');
|
|
16
|
+
return { workspaceId: opts.workspace, workspaceEpoch: opts.epoch, confirm: true, input };
|
|
17
|
+
};
|
|
18
|
+
reviewed(group.command('configure').requiredOption('--file <path>', 'owner-reviewed target JSON: expectedRevision, enabled, definition, confirmDaemonAccess'))
|
|
19
|
+
.action(async (opts) => {
|
|
20
|
+
const st = fs.lstatSync(opts.file);
|
|
21
|
+
if (!st.isFile() || st.isSymbolicLink() || st.size > 128 * 1024)
|
|
22
|
+
throw new DodoError('INVALID_INPUT', 'target configuration must be a regular JSON file at most 128 KiB');
|
|
23
|
+
let input;
|
|
24
|
+
try {
|
|
25
|
+
input = JSON.parse(fs.readFileSync(opts.file, 'utf8'));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw new DodoError('INVALID_INPUT', 'invalid target JSON');
|
|
29
|
+
}
|
|
30
|
+
print(await ipc('deployment.configure', envelope(opts, input)));
|
|
31
|
+
});
|
|
32
|
+
reviewed(group.command('prepare').requiredOption('--target <id>', 'owner-registered target ID').requiredOption('--revision <n>', 'target revision')
|
|
33
|
+
.requiredOption('--verification <id>', 'current VERIFIED verification ID').requiredOption('--key <key>', 'idempotency key; reuse for retries'))
|
|
34
|
+
.action(async (opts) => print(await ipc('deployment.prepare', envelope(opts, {
|
|
35
|
+
targetId: opts.target, expectedTargetRevision: Number(opts.revision), verificationId: opts.verification, idempotencyKey: opts.key,
|
|
36
|
+
}))));
|
|
37
|
+
reviewed(group.command('build <deploymentId>').requiredOption('--hash <hash>', 'reviewed plan hash'))
|
|
38
|
+
.action(async (deploymentId, opts) => print(await ipc('deployment.build', envelope(opts, { deploymentId, planHash: opts.hash }))));
|
|
39
|
+
reviewed(group.command('apply <deploymentId>').requiredOption('--hash <hash>', 'reviewed plan hash').requiredOption('--image <digest>', 'reviewed immutable image digest'))
|
|
40
|
+
.action(async (deploymentId, opts) => print(await ipc('deployment.apply', envelope(opts, { deploymentId, planHash: opts.hash, imageDigest: opts.image }))));
|
|
41
|
+
for (const op of ['observe', 'source-preview'])
|
|
42
|
+
reviewed(group.command(`${op} <deploymentId>`))
|
|
43
|
+
.action(async (deploymentId, opts) => print(await ipc('deployment.' + op.replaceAll('-', '_'), envelope(opts, { deploymentId }))));
|
|
44
|
+
reviewed(group.command('maintenance').requiredOption('--file <path>', 'owner-reviewed maintenance JSON; preview returns a review ID/hash for apply'))
|
|
45
|
+
.action(async (opts) => {
|
|
46
|
+
const st = fs.lstatSync(opts.file);
|
|
47
|
+
if (!st.isFile() || st.isSymbolicLink() || st.nlink !== 1 || st.size > 65536)
|
|
48
|
+
throw new DodoError('INVALID_INPUT', 'maintenance JSON must be a bounded regular file');
|
|
49
|
+
let input;
|
|
50
|
+
try {
|
|
51
|
+
input = JSON.parse(fs.readFileSync(opts.file, 'utf8'));
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new DodoError('INVALID_INPUT', 'invalid maintenance JSON');
|
|
55
|
+
}
|
|
56
|
+
print(await ipc('deployment.maintenance', envelope(opts, input)));
|
|
57
|
+
});
|
|
58
|
+
reviewed(group.command('rollback-prepare <deploymentId>').requiredOption('--key <key>', 'idempotency key for this rollback review'))
|
|
59
|
+
.action(async (deploymentId, opts) => print(await ipc('deployment.rollback_prepare', envelope(opts, { deploymentId, idempotencyKey: opts.key }))));
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=deployment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../src/cli/deployment.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/main.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
const invokedCwd = process.cwd();
|
|
8
8
|
import fs from 'node:fs';
|
|
9
9
|
import { Command } from 'commander';
|
|
10
|
+
import { registerDataRecoveryCommands } from './dataRecovery.js';
|
|
11
|
+
import { registerDeploymentCommands } from './deployment.js';
|
|
10
12
|
import { startServer, DODO_VERSION } from '../server/appServer.js';
|
|
11
13
|
import { startStdioServer } from '../server/stdioServer.js';
|
|
12
14
|
import { resolveConfigDir, ensureConfigDir, statePaths, ipcSocketPath } from '../config/paths.js';
|
|
@@ -16,6 +18,7 @@ import { mintWorkspaceId } from '../workspace/identity.js';
|
|
|
16
18
|
import { openDatabase, openDatabaseReadonly } from '../store/db.js';
|
|
17
19
|
import { Store } from '../store/store.js';
|
|
18
20
|
import { ipcCall, IpcError } from '../ipc/client.js';
|
|
21
|
+
import { ownerCommandTimeout } from '../ipc/timeouts.js';
|
|
19
22
|
import { installationIpcCall } from '../ipc/installationClient.js';
|
|
20
23
|
import { formatTerminalLine } from './terminal.js';
|
|
21
24
|
import { TRUST_MODE_DESCRIPTIONS } from '../security/policy.js';
|
|
@@ -31,6 +34,7 @@ import { runCliMenu } from './menu.js';
|
|
|
31
34
|
import { TunnelRuntime } from '../tunnel/runtime.js';
|
|
32
35
|
import { INSTALLATION_AUTHORITY_ID } from '../auth/constants.js';
|
|
33
36
|
const program = new Command();
|
|
37
|
+
registerDeploymentCommands(program, ipcForCwd);
|
|
34
38
|
program.name('dodo').description('DODO — local-first, single-owner, project-scoped coding MCP server').version(DODO_VERSION);
|
|
35
39
|
function fail(message, code = 1) {
|
|
36
40
|
console.error(`dodo: ${message}`);
|
|
@@ -61,7 +65,7 @@ function workspaceIpcPath(root) {
|
|
|
61
65
|
}
|
|
62
66
|
async function ipcForCwd(cmd, args = {}) {
|
|
63
67
|
const { ipcPath } = workspaceIpcPath();
|
|
64
|
-
return ipcCall(ipcPath, cmd, args);
|
|
68
|
+
return ipcCall(ipcPath, cmd, args, ownerCommandTimeout(cmd));
|
|
65
69
|
}
|
|
66
70
|
/** OAuth identity belongs to the installation, not the shell's CWD. */
|
|
67
71
|
async function ipcForInstallation(cmd, args = {}) {
|
|
@@ -1268,6 +1272,36 @@ auth
|
|
|
1268
1272
|
throw err;
|
|
1269
1273
|
}
|
|
1270
1274
|
});
|
|
1275
|
+
// -------------------------------------------------------------- recovery ---
|
|
1276
|
+
const recovery = program.command('recovery').description('inspect or configure automatic source backups for the current registered project');
|
|
1277
|
+
registerDataRecoveryCommands(recovery, ipcForCwd);
|
|
1278
|
+
recovery.command('status').action(async () => console.log(JSON.stringify(await ipcForCwd('recovery.status'), null, 2)));
|
|
1279
|
+
recovery.command('scan').option('--cursor <n>', 'page offset', '0').option('--limit <n>', 'page size (1–100)', '50').action(async (opts) => console.log(JSON.stringify(await ipcForCwd('recovery.drift.scan', { cursor: Number(opts.cursor), limit: Number(opts.limit) }), null, 2)));
|
|
1280
|
+
recovery.command('acknowledge <digest>').requiredOption('--workspace <id>', 'reviewed workspace ID').requiredOption('--epoch <epoch>', 'reviewed workspace epoch').option('--yes', 'accept exactly the reviewed observed state', false)
|
|
1281
|
+
.action(async (digest, opts) => { if (!opts.yes)
|
|
1282
|
+
throw new DodoError('INVALID_INPUT', 'review drift then add --yes'); console.log(JSON.stringify(await ipcForCwd('recovery.drift.acknowledge', { digest, workspaceId: opts.workspace, workspaceEpoch: opts.epoch, confirm: true }), null, 2)); });
|
|
1283
|
+
recovery.command('evidence').option('--id <verificationId>', 'refresh evidence for a specific verification').action(async (opts) => console.log(JSON.stringify(await ipcForCwd(opts.id ? 'recovery.evidence.inspect' : 'recovery.evidence.list', opts.id ? { verificationId: opts.id } : {}), null, 2)));
|
|
1284
|
+
recovery.command('cleanup-preview').action(async () => console.log(JSON.stringify(await ipcForCwd('recovery.cleanup.preview'), null, 2)));
|
|
1285
|
+
recovery.command('mark <name> <checkpointId>').requiredOption('--revision <n>', 'reviewed pointer revision; 0 for a new name').requiredOption('--workspace <id>', 'reviewed workspace ID').requiredOption('--epoch <epoch>', 'reviewed epoch').option('--yes', 'confirm owner label (does not certify tests)', false)
|
|
1286
|
+
.action(async (name, checkpointId, opts) => { if (!opts.yes)
|
|
1287
|
+
throw new DodoError('INVALID_INPUT', 'review checkpoint and add --yes'); console.log(JSON.stringify(await ipcForCwd('recovery.mark', { name, snapshotId: checkpointId, expectedRevision: Number(opts.revision), workspaceId: opts.workspace, workspaceEpoch: opts.epoch, confirm: true }), null, 2)); });
|
|
1288
|
+
recovery.command('checkpoint').action(async () => console.log(JSON.stringify(await ipcForCwd('recovery.checkpoint'), null, 2)));
|
|
1289
|
+
recovery.command('list').option('--sessions', 'list sessions instead of checkpoints', false).action(async (opts) => console.log(JSON.stringify(await ipcForCwd(opts.sessions ? 'recovery.recovery_session_list' : 'recovery.checkpoint_list'), null, 2)));
|
|
1290
|
+
recovery.command('preview <id>').option('--session', 'undo caller session receipts', false).option('--path <relative>', 'select a file or directory').option('--exact-mirror', 'explicitly include extra source-file deletions', false)
|
|
1291
|
+
.action(async (id, opts) => console.log(JSON.stringify(await ipcForCwd('recovery.restore_preview', { ...(opts.session ? { sessionId: id } : { checkpointId: id }), ...(opts.path ? { paths: [opts.path] } : {}), exactMirror: opts.exactMirror }), null, 2)));
|
|
1292
|
+
recovery.command('apply <planId>').requiredOption('--hash <hash>', 'exact reviewed planHash').requiredOption('--key <key>', 'durable idempotency key; reuse for retries').requiredOption('--workspace <id>', 'reviewed workspace ID').requiredOption('--epoch <epoch>', 'reviewed workspace epoch').option('--yes', 'confirm exactly this reviewed plan', false)
|
|
1293
|
+
.action(async (planId, opts) => {
|
|
1294
|
+
if (!opts.yes)
|
|
1295
|
+
fail('review the preview, then pass --yes with the same plan/hash and workspace context');
|
|
1296
|
+
console.log(JSON.stringify(await ipcForCwd('recovery.restore_apply', { planId, planHash: opts.hash, idempotencyKey: opts.key, workspaceId: opts.workspace, workspaceEpoch: opts.epoch, confirm: true }), null, 2));
|
|
1297
|
+
});
|
|
1298
|
+
recovery.command('configure').option('--enabled <value>', 'true or false').option('--yes', 'confirm the owner policy change', false)
|
|
1299
|
+
.action(async (opts) => {
|
|
1300
|
+
if (!opts.yes || !['true', 'false'].includes(opts.enabled ?? ''))
|
|
1301
|
+
fail('use --enabled true|false --yes to confirm');
|
|
1302
|
+
const current = await ipcForCwd('recovery.status');
|
|
1303
|
+
console.log(JSON.stringify(await ipcForCwd('recovery.configure', { policy: { ...current.policy, enabled: opts.enabled === 'true' }, confirm: true }), null, 2));
|
|
1304
|
+
});
|
|
1271
1305
|
// --------------------------------------------------------------- recover ---
|
|
1272
1306
|
program
|
|
1273
1307
|
.command('recover')
|