@aitne-sh/aitne 0.1.4 → 0.1.5

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.
@@ -1,166 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * In-process smoke test for the Obsidian API routes.
4
- *
5
- * Purpose: verify empirically that the new PUT/DELETE endpoints — and
6
- * the `path=` CLI semantics they rely on — actually work against the
7
- * real Obsidian CLI and a real vault. The vitest suite mocks the
8
- * ObsidianService entirely, so it cannot catch wrong argument names,
9
- * missing CLI flags, or vault-level semantic mismatches.
10
- *
11
- * Strategy: mount the freshly-built routes against a real
12
- * ObsidianService pointing at the real vault, then drive the full
13
- * CRUD lifecycle via Hono's in-process `app.request`. No daemon
14
- * restart, no network, no port conflict.
15
- *
16
- * Safety:
17
- * - All writes target a single `__smoketest_obsidian_api.md` path
18
- * prefixed with `__` so it's visually obvious in the vault.
19
- * - The lifecycle ends with DELETE, so a successful run leaves no
20
- * residue.
21
- * - On any failure we attempt a best-effort DELETE before exiting.
22
- */
23
-
24
- import { createObsidianRoutes } from "../packages/daemon/dist/api/routes/obsidian.js";
25
- import { ObsidianService } from "../packages/daemon/dist/services/obsidian.js";
26
-
27
- const TEST_PATH = "__smoketest_obsidian_api";
28
- const VAULT_PATH =
29
- process.env.PA_EXTERNAL_OBSIDIAN_VAULT_PATH ??
30
- process.env.PA_OBSIDIAN_VAULT_PATH ??
31
- "/Users/test/Library/Mobile Documents/iCloud~md~obsidian/Documents/personal-agent";
32
- const VAULT_NAME =
33
- process.env.PA_EXTERNAL_OBSIDIAN_VAULT_NAME ??
34
- process.env.PA_OBSIDIAN_VAULT_NAME ??
35
- "personal-agent";
36
-
37
- const config = {
38
- externalObsidianVaultPath: VAULT_PATH,
39
- externalObsidianVaultName: VAULT_NAME,
40
- };
41
-
42
- const service = new ObsidianService(config);
43
- const app = createObsidianRoutes({ obsidianService: service });
44
-
45
- let pass = 0;
46
- let fail = 0;
47
- const failures = [];
48
-
49
- function ok(label, cond, detail) {
50
- if (cond) {
51
- pass += 1;
52
- console.log(` \u2713 ${label}`);
53
- } else {
54
- fail += 1;
55
- failures.push(`${label}${detail ? ` — ${detail}` : ""}`);
56
- console.log(` \u2717 ${label}${detail ? ` — ${detail}` : ""}`);
57
- }
58
- }
59
-
60
- async function request(method, path, body) {
61
- const init = { method };
62
- if (body !== undefined) {
63
- init.headers = { "Content-Type": "application/json" };
64
- init.body = JSON.stringify(body);
65
- }
66
- const res = await app.request(path, init);
67
- let json = null;
68
- try {
69
- json = await res.json();
70
- } catch {}
71
- return { status: res.status, json };
72
- }
73
-
74
- async function bestEffortCleanup() {
75
- try {
76
- await request("DELETE", `/obsidian/notes/${TEST_PATH}`);
77
- } catch {}
78
- }
79
-
80
- async function main() {
81
- console.log(`Vault: ${VAULT_PATH}`);
82
- console.log(`Test path: ${TEST_PATH}.md`);
83
- console.log();
84
-
85
- // --- Precondition: status ---
86
- console.log("1. Precondition");
87
- const status = await request("GET", "/obsidian/status");
88
- ok("status=200", status.status === 200);
89
- ok("available=true", status.json?.available === true, JSON.stringify(status.json));
90
- ok("obsidianRunning=true", status.json?.obsidianRunning === true, JSON.stringify(status.json));
91
- if (status.json?.obsidianRunning !== true) {
92
- console.error("\nObsidian app is not running — aborting smoke test.");
93
- process.exit(2);
94
- }
95
-
96
- // Make sure we start clean (in case a previous run crashed mid-lifecycle).
97
- await bestEffortCleanup();
98
-
99
- // --- Step 2: PUT creates a new note (idempotent create-or-replace) ---
100
- console.log("\n2. PUT create-path");
101
- const body1 = "# Smoke test v1\n\nLine A\n";
102
- const put1 = await request("PUT", `/obsidian/notes/${TEST_PATH}`, { content: body1 });
103
- ok("PUT status=200", put1.status === 200, `got ${put1.status} ${JSON.stringify(put1.json)}`);
104
- ok("PUT status field=updated", put1.json?.status === "updated");
105
-
106
- // --- Step 3: GET returns the created content ---
107
- console.log("\n3. GET read back");
108
- const get1 = await request("GET", `/obsidian/notes/${TEST_PATH}`);
109
- ok("GET status=200", get1.status === 200);
110
- ok(
111
- "GET content matches v1",
112
- typeof get1.json?.content === "string" && get1.json.content.includes("Line A"),
113
- `got ${JSON.stringify(get1.json?.content)?.slice(0, 80)}`,
114
- );
115
-
116
- // --- Step 4: PUT overwrites with new content ---
117
- console.log("\n4. PUT overwrite");
118
- const body2 = "# Smoke test v2\n\nLine B only\n";
119
- const put2 = await request("PUT", `/obsidian/notes/${TEST_PATH}`, { content: body2 });
120
- ok("PUT status=200", put2.status === 200);
121
-
122
- const get2 = await request("GET", `/obsidian/notes/${TEST_PATH}`);
123
- ok("GET status=200", get2.status === 200);
124
- ok(
125
- "GET content matches v2",
126
- typeof get2.json?.content === "string"
127
- && get2.json.content.includes("Line B only")
128
- && !get2.json.content.includes("Line A"),
129
- `got ${JSON.stringify(get2.json?.content)?.slice(0, 80)}`,
130
- );
131
-
132
- // --- Step 5: DELETE removes the note ---
133
- console.log("\n5. DELETE");
134
- const del1 = await request("DELETE", `/obsidian/notes/${TEST_PATH}`);
135
- ok("DELETE status=200", del1.status === 200, `got ${del1.status} ${JSON.stringify(del1.json)}`);
136
- ok("DELETE status field=deleted", del1.json?.status === "deleted");
137
- ok("DELETE permanent=false (default)", del1.json?.permanent === false);
138
-
139
- // --- Step 6: DELETE again → 404 (idempotent) ---
140
- console.log("\n6. DELETE idempotent 404");
141
- const del2 = await request("DELETE", `/obsidian/notes/${TEST_PATH}`);
142
- ok("Second DELETE status=404", del2.status === 404, `got ${del2.status} ${JSON.stringify(del2.json)}`);
143
- ok("error=not_found", del2.json?.error === "not_found");
144
-
145
- // --- Step 7: GET after delete → 404 ---
146
- console.log("\n7. GET after delete");
147
- const get3 = await request("GET", `/obsidian/notes/${TEST_PATH}`);
148
- ok("GET status=404", get3.status === 404, `got ${get3.status} ${JSON.stringify(get3.json)}`);
149
-
150
- // --- Summary ---
151
- console.log();
152
- console.log("─".repeat(48));
153
- console.log(`Passed: ${pass} Failed: ${fail}`);
154
- if (fail > 0) {
155
- console.log("\nFailures:");
156
- for (const f of failures) console.log(` - ${f}`);
157
- process.exit(1);
158
- }
159
- console.log("All smoke checks passed.");
160
- }
161
-
162
- main().catch(async (err) => {
163
- console.error("Smoke test threw:", err);
164
- await bestEffortCleanup();
165
- process.exit(1);
166
- });