@njeybe/nativ 2.0.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.
Files changed (140) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/LICENSE +21 -0
  3. package/README.md +334 -0
  4. package/bin/cli.js +31 -0
  5. package/dist/commands/bench.d.ts +8 -0
  6. package/dist/commands/bench.js +52 -0
  7. package/dist/commands/db.d.ts +22 -0
  8. package/dist/commands/db.js +415 -0
  9. package/dist/commands/doctor.d.ts +38 -0
  10. package/dist/commands/doctor.js +169 -0
  11. package/dist/commands/hook.d.ts +31 -0
  12. package/dist/commands/hook.js +105 -0
  13. package/dist/commands/init.d.ts +3 -0
  14. package/dist/commands/init.js +144 -0
  15. package/dist/commands/mcp.d.ts +5 -0
  16. package/dist/commands/mcp.js +16 -0
  17. package/dist/commands/setup.d.ts +17 -0
  18. package/dist/commands/setup.js +51 -0
  19. package/dist/commands/status.d.ts +5 -0
  20. package/dist/commands/status.js +75 -0
  21. package/dist/commands/task.d.ts +83 -0
  22. package/dist/commands/task.js +807 -0
  23. package/dist/commands/test-gen.d.ts +14 -0
  24. package/dist/commands/test-gen.js +52 -0
  25. package/dist/commands/triage.d.ts +70 -0
  26. package/dist/commands/triage.js +343 -0
  27. package/dist/commands/update.d.ts +14 -0
  28. package/dist/commands/update.js +112 -0
  29. package/dist/commands/validate.d.ts +1 -0
  30. package/dist/commands/validate.js +89 -0
  31. package/dist/commands/verify.d.ts +8 -0
  32. package/dist/commands/verify.js +65 -0
  33. package/dist/commands/worktree.d.ts +47 -0
  34. package/dist/commands/worktree.js +396 -0
  35. package/dist/core/benchmark.d.ts +57 -0
  36. package/dist/core/benchmark.js +772 -0
  37. package/dist/core/enforcement.d.ts +80 -0
  38. package/dist/core/enforcement.js +271 -0
  39. package/dist/core/legacy-templates.d.ts +24 -0
  40. package/dist/core/legacy-templates.js +60 -0
  41. package/dist/core/lock-manager.d.ts +54 -0
  42. package/dist/core/lock-manager.js +260 -0
  43. package/dist/core/root-resolver.d.ts +32 -0
  44. package/dist/core/root-resolver.js +149 -0
  45. package/dist/core/setup-assets.d.ts +123 -0
  46. package/dist/core/setup-assets.js +438 -0
  47. package/dist/core/telemetry.d.ts +156 -0
  48. package/dist/core/telemetry.js +416 -0
  49. package/dist/core/test-generator-types.d.ts +227 -0
  50. package/dist/core/test-generator-types.js +179 -0
  51. package/dist/core/test-generator.d.ts +34 -0
  52. package/dist/core/test-generator.js +1690 -0
  53. package/dist/core/tier1-liaison.d.ts +139 -0
  54. package/dist/core/tier1-liaison.js +320 -0
  55. package/dist/core/verifier.d.ts +52 -0
  56. package/dist/core/verifier.js +249 -0
  57. package/dist/core/version.d.ts +5 -0
  58. package/dist/core/version.js +14 -0
  59. package/dist/core/worktree-merge.d.ts +30 -0
  60. package/dist/core/worktree-merge.js +98 -0
  61. package/dist/db/data-engine.d.ts +46 -0
  62. package/dist/db/data-engine.js +802 -0
  63. package/dist/db/diff.d.ts +39 -0
  64. package/dist/db/diff.js +420 -0
  65. package/dist/db/env-parser.d.ts +86 -0
  66. package/dist/db/env-parser.js +549 -0
  67. package/dist/db/introspector.d.ts +21 -0
  68. package/dist/db/introspector.js +835 -0
  69. package/dist/db/types.d.ts +217 -0
  70. package/dist/db/types.js +9 -0
  71. package/dist/governor/circuit-breaker.d.ts +100 -0
  72. package/dist/governor/circuit-breaker.js +231 -0
  73. package/dist/governor/evaluator.d.ts +67 -0
  74. package/dist/governor/evaluator.js +851 -0
  75. package/dist/governor/index.d.ts +6 -0
  76. package/dist/governor/index.js +6 -0
  77. package/dist/governor/rules/api-rules.d.ts +2 -0
  78. package/dist/governor/rules/api-rules.js +140 -0
  79. package/dist/governor/rules/db-rules.d.ts +2 -0
  80. package/dist/governor/rules/db-rules.js +180 -0
  81. package/dist/governor/store.d.ts +33 -0
  82. package/dist/governor/store.js +84 -0
  83. package/dist/governor/types.d.ts +64 -0
  84. package/dist/governor/types.js +1 -0
  85. package/dist/index.d.ts +3 -0
  86. package/dist/index.js +358 -0
  87. package/dist/mcp/server.d.ts +3 -0
  88. package/dist/mcp/server.js +309 -0
  89. package/dist/providers/claude-api.d.ts +5 -0
  90. package/dist/providers/claude-api.js +75 -0
  91. package/dist/providers/claude-cli.d.ts +13 -0
  92. package/dist/providers/claude-cli.js +134 -0
  93. package/dist/providers/gemini.d.ts +8 -0
  94. package/dist/providers/gemini.js +78 -0
  95. package/dist/providers/index.d.ts +5 -0
  96. package/dist/providers/index.js +5 -0
  97. package/dist/providers/registry.d.ts +38 -0
  98. package/dist/providers/registry.js +121 -0
  99. package/dist/providers/types.d.ts +74 -0
  100. package/dist/providers/types.js +25 -0
  101. package/dist/runner/agent-supervisor.d.ts +363 -0
  102. package/dist/runner/agent-supervisor.js +1672 -0
  103. package/dist/scanner/context-builder.d.ts +2 -0
  104. package/dist/scanner/context-builder.js +29 -0
  105. package/dist/scanner/detector.d.ts +2 -0
  106. package/dist/scanner/detector.js +760 -0
  107. package/dist/scanner/types.d.ts +80 -0
  108. package/dist/scanner/types.js +50 -0
  109. package/dist/server/studio-server.d.ts +39 -0
  110. package/dist/server/studio-server.js +1931 -0
  111. package/dist/server/studio-ui.d.ts +15 -0
  112. package/dist/server/studio-ui.js +5321 -0
  113. package/package.json +70 -0
  114. package/plugin/.claude-plugin/plugin.json +18 -0
  115. package/plugin/.mcp.json +10 -0
  116. package/plugin/agents/architect.md +28 -0
  117. package/plugin/agents/verifier.md +28 -0
  118. package/plugin/agents/worker.md +26 -0
  119. package/plugin/hooks/hooks.json +28 -0
  120. package/plugin/skills/nativ/SKILL.md +75 -0
  121. package/templates/.claudeignore +45 -0
  122. package/templates/AGENTS.md +67 -0
  123. package/templates/CLAUDE.md +32 -0
  124. package/templates/GEMINI.md +66 -0
  125. package/templates/claude-agents/architect.md +28 -0
  126. package/templates/claude-agents/verifier.md +28 -0
  127. package/templates/claude-agents/worker.md +26 -0
  128. package/templates/dot-ai/api_contracts.json +66 -0
  129. package/templates/dot-ai/context.md +38 -0
  130. package/templates/dot-ai/db_schema.json +39 -0
  131. package/templates/dot-ai/master_plan.json +28 -0
  132. package/templates/dot-ai/subagents/backend.md +11 -0
  133. package/templates/dot-ai/subagents/database.md +10 -0
  134. package/templates/dot-ai/subagents/db-migration.md +11 -0
  135. package/templates/dot-ai/subagents/devops-agent.md +11 -0
  136. package/templates/dot-ai/subagents/flutter-developer.md +11 -0
  137. package/templates/dot-ai/subagents/frontend.md +126 -0
  138. package/templates/dot-ai/subagents/qa-tester.md +13 -0
  139. package/templates/dot-ai/subagents/security-auditor.md +11 -0
  140. package/templates/dot-ai/ui_specs.md +78 -0
@@ -0,0 +1,249 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { exec } from 'node:child_process';
4
+ export function loadMasterPlan(targetDir) {
5
+ const planPath = path.join(targetDir, '.ai', 'master_plan.json');
6
+ if (!fs.existsSync(planPath)) {
7
+ return { planPath, plan: null, error: `No .ai/master_plan.json found at: ${planPath}` };
8
+ }
9
+ try {
10
+ const raw = fs.readFileSync(planPath, 'utf8');
11
+ const plan = JSON.parse(raw);
12
+ return { planPath, plan };
13
+ }
14
+ catch (err) {
15
+ return { planPath, plan: null, error: `Failed to parse .ai/master_plan.json: ${err.message}` };
16
+ }
17
+ }
18
+ /**
19
+ * Execute a verification command in the workspace directory with timeout and output capture.
20
+ */
21
+ export async function executeVerification(command, cwd, timeoutMs = 120_000) {
22
+ const trimmed = (command || '').trim();
23
+ // Treat empty, 'none', or 'skip' as an informational pass
24
+ if (!trimmed || trimmed.toLowerCase() === 'none' || trimmed.toLowerCase() === 'skip') {
25
+ return {
26
+ success: true,
27
+ exitCode: 0,
28
+ command: trimmed || 'none',
29
+ stdout: '',
30
+ stderr: '',
31
+ durationMs: 0,
32
+ skipped: true,
33
+ };
34
+ }
35
+ // Cross-platform compatibility for common test commands on Windows cmd.exe
36
+ let finalCommand = trimmed;
37
+ if (process.platform === 'win32') {
38
+ if (trimmed === 'true')
39
+ finalCommand = 'exit 0';
40
+ else if (trimmed === 'false')
41
+ finalCommand = 'exit 1';
42
+ }
43
+ const start = Date.now();
44
+ return new Promise((resolve) => {
45
+ exec(finalCommand, {
46
+ cwd,
47
+ timeout: timeoutMs,
48
+ maxBuffer: 10 * 1024 * 1024,
49
+ env: process.env,
50
+ }, (err, stdout, stderr) => {
51
+ const durationMs = Date.now() - start;
52
+ const out = (stdout || '').toString();
53
+ const errOut = (stderr || '').toString();
54
+ if (err) {
55
+ const exitCode = typeof err.code === 'number' ? err.code : 1;
56
+ resolve({
57
+ success: false,
58
+ exitCode,
59
+ command: trimmed,
60
+ stdout: out,
61
+ stderr: errOut || err.message,
62
+ durationMs,
63
+ error: err.killed ? `Command timed out after ${timeoutMs}ms` : err.message,
64
+ });
65
+ }
66
+ else {
67
+ resolve({
68
+ success: true,
69
+ exitCode: 0,
70
+ command: trimmed,
71
+ stdout: out,
72
+ stderr: errOut,
73
+ durationMs,
74
+ });
75
+ }
76
+ });
77
+ });
78
+ }
79
+ /**
80
+ * Run verification for a single specific task in the plan.
81
+ */
82
+ export async function verifyTask(taskId, targetDirArg, options = {}) {
83
+ const targetDir = path.resolve(targetDirArg || process.cwd());
84
+ const { plan, error } = loadMasterPlan(targetDir);
85
+ if (!plan) {
86
+ return {
87
+ taskId,
88
+ title: 'Unknown',
89
+ milestoneId: 'unknown',
90
+ milestoneName: 'Unknown',
91
+ status: 'unknown',
92
+ result: {
93
+ success: false,
94
+ exitCode: 1,
95
+ command: '',
96
+ stdout: '',
97
+ stderr: error || 'Failed to load master plan',
98
+ durationMs: 0,
99
+ error: error || 'Failed to load master plan',
100
+ },
101
+ };
102
+ }
103
+ let foundTask = null;
104
+ let foundMilestone = null;
105
+ for (const m of plan.milestones) {
106
+ const t = m.tasks.find((item) => item.id === taskId);
107
+ if (t) {
108
+ foundTask = t;
109
+ foundMilestone = m;
110
+ break;
111
+ }
112
+ }
113
+ if (!foundTask || !foundMilestone) {
114
+ return {
115
+ taskId,
116
+ title: 'Not Found',
117
+ milestoneId: 'unknown',
118
+ milestoneName: 'Unknown',
119
+ status: 'unknown',
120
+ result: {
121
+ success: false,
122
+ exitCode: 1,
123
+ command: '',
124
+ stdout: '',
125
+ stderr: `Task [${taskId}] not found in .ai/master_plan.json`,
126
+ durationMs: 0,
127
+ error: `Task [${taskId}] not found`,
128
+ },
129
+ };
130
+ }
131
+ const result = await executeVerification(foundTask.verificationCommand, targetDir, options.timeout);
132
+ return {
133
+ taskId: foundTask.id,
134
+ title: foundTask.title,
135
+ milestoneId: foundMilestone.id,
136
+ milestoneName: foundMilestone.name,
137
+ status: foundTask.status,
138
+ result,
139
+ };
140
+ }
141
+ /**
142
+ * Verify a batch of tasks (by milestone, all completed tasks, or the active in-progress task).
143
+ */
144
+ export async function verifyBatch(targetDirArg, options = {}) {
145
+ const targetDir = path.resolve(targetDirArg || process.cwd());
146
+ const { plan, error } = loadMasterPlan(targetDir);
147
+ if (!plan) {
148
+ return {
149
+ projectName: 'unknown',
150
+ total: 0,
151
+ passed: 0,
152
+ failed: 1,
153
+ skipped: 0,
154
+ durationMs: 0,
155
+ tasks: [
156
+ {
157
+ taskId: 'init',
158
+ title: 'Plan Loader',
159
+ milestoneId: 'unknown',
160
+ milestoneName: 'Unknown',
161
+ status: 'unknown',
162
+ result: {
163
+ success: false,
164
+ exitCode: 1,
165
+ command: '',
166
+ stdout: '',
167
+ stderr: error || 'Plan not found',
168
+ durationMs: 0,
169
+ error: error || 'Plan not found',
170
+ },
171
+ },
172
+ ],
173
+ };
174
+ }
175
+ // Filter tasks to run
176
+ const candidates = [];
177
+ for (const m of plan.milestones) {
178
+ for (const t of m.tasks) {
179
+ if (options.taskId && t.id === options.taskId) {
180
+ candidates.push({ task: t, milestone: m });
181
+ }
182
+ else if (options.milestoneId && (m.id === options.milestoneId || m.name.toLowerCase() === options.milestoneId.toLowerCase())) {
183
+ candidates.push({ task: t, milestone: m });
184
+ }
185
+ else if (options.all) {
186
+ // All tasks with verification commands (prefer completed or in_progress, but include all)
187
+ candidates.push({ task: t, milestone: m });
188
+ }
189
+ }
190
+ }
191
+ // If no filters specified, find the current in_progress task, or next ready task
192
+ if (!options.taskId && !options.milestoneId && !options.all) {
193
+ let activeTask = null;
194
+ for (const m of plan.milestones) {
195
+ const inProgress = m.tasks.find((t) => t.status === 'in_progress');
196
+ if (inProgress) {
197
+ activeTask = { task: inProgress, milestone: m };
198
+ break;
199
+ }
200
+ }
201
+ if (!activeTask) {
202
+ for (const m of plan.milestones) {
203
+ const pending = m.tasks.find((t) => t.status === 'pending');
204
+ if (pending) {
205
+ activeTask = { task: pending, milestone: m };
206
+ break;
207
+ }
208
+ }
209
+ }
210
+ if (activeTask) {
211
+ candidates.push(activeTask);
212
+ }
213
+ }
214
+ const results = [];
215
+ let passed = 0;
216
+ let failed = 0;
217
+ let skipped = 0;
218
+ let totalDuration = 0;
219
+ for (const { task, milestone } of candidates) {
220
+ const vResult = await executeVerification(task.verificationCommand, targetDir, options.timeout);
221
+ totalDuration += vResult.durationMs;
222
+ if (vResult.skipped) {
223
+ skipped++;
224
+ }
225
+ else if (vResult.success) {
226
+ passed++;
227
+ }
228
+ else {
229
+ failed++;
230
+ }
231
+ results.push({
232
+ taskId: task.id,
233
+ title: task.title,
234
+ milestoneId: milestone.id,
235
+ milestoneName: milestone.name,
236
+ status: task.status,
237
+ result: vResult,
238
+ });
239
+ }
240
+ return {
241
+ projectName: plan.projectName,
242
+ total: candidates.length,
243
+ passed,
244
+ failed,
245
+ skipped,
246
+ durationMs: totalDuration,
247
+ tasks: results,
248
+ };
249
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * The installed package's version, read from package.json so `nativ --version`, the MCP server info and the
3
+ * plugin can never disagree with what was published. Works from dist/ (dist/core/version.js -> ../../package.json).
4
+ */
5
+ export declare function packageVersion(): string;
@@ -0,0 +1,14 @@
1
+ import fs from 'node:fs';
2
+ /**
3
+ * The installed package's version, read from package.json so `nativ --version`, the MCP server info and the
4
+ * plugin can never disagree with what was published. Works from dist/ (dist/core/version.js -> ../../package.json).
5
+ */
6
+ export function packageVersion() {
7
+ try {
8
+ const pkg = JSON.parse(fs.readFileSync(new URL('../../package.json', import.meta.url), 'utf8'));
9
+ return typeof pkg.version === 'string' && pkg.version ? pkg.version : '0.0.0';
10
+ }
11
+ catch {
12
+ return '0.0.0';
13
+ }
14
+ }
@@ -0,0 +1,30 @@
1
+ export interface WorktreeMergeOutcome {
2
+ merged: boolean;
3
+ /** The agent left uncommitted changes; they were committed on the agent branch before merging. */
4
+ committedPendingWork: boolean;
5
+ /** Commit created for the pending work, when there was any. */
6
+ pendingCommit: string | null;
7
+ /** The worktree directory and agent branch were removed (only after a successful merge). */
8
+ cleanedUp: boolean;
9
+ message: string;
10
+ }
11
+ export declare class WorktreeMergeError extends Error {
12
+ /** True when the worktree and agent branch were left in place with all work intact. */
13
+ readonly workPreserved: boolean;
14
+ constructor(message: string,
15
+ /** True when the worktree and agent branch were left in place with all work intact. */
16
+ workPreserved: boolean);
17
+ }
18
+ /**
19
+ * Merges `agent/task-<id>` back into the current branch without ever losing agent work:
20
+ *
21
+ * 1. Uncommitted changes in the worktree are committed on the agent branch first — the
22
+ * verification gatekeeper checked the working tree, so that state is what gets merged.
23
+ * 2. The branch is merged. On failure (e.g. conflicts) the merge is aborted and the
24
+ * worktree and branch are left exactly as they were.
25
+ * 3. Only after a successful merge is the worktree removed and the (now merged) branch
26
+ * deleted with the safe `-d`.
27
+ *
28
+ * Git hooks run normally; a failing hook stops the merge with the work preserved.
29
+ */
30
+ export declare function mergeAgentWorktree(rootDir: string, taskId: string): WorktreeMergeOutcome;
@@ -0,0 +1,98 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { spawnSync } from 'node:child_process';
4
+ import { linkWorktreeAiDirectory, linkWorktreeNodeModules, safeUnlinkWorktreeAiDirectory, safeUnlinkWorktreeNodeModules, } from './root-resolver.js';
5
+ export class WorktreeMergeError extends Error {
6
+ workPreserved;
7
+ constructor(message,
8
+ /** True when the worktree and agent branch were left in place with all work intact. */
9
+ workPreserved) {
10
+ super(message);
11
+ this.workPreserved = workPreserved;
12
+ this.name = 'WorktreeMergeError';
13
+ }
14
+ }
15
+ function git(cwd, args) {
16
+ const res = spawnSync('git', args, { cwd, encoding: 'utf8', windowsHide: true, maxBuffer: 64 * 1024 * 1024 });
17
+ return { ok: res.status === 0, out: `${res.stdout ?? ''}${res.stderr ?? ''}`.trim() };
18
+ }
19
+ function remount(worktreeDir, rootDir) {
20
+ linkWorktreeAiDirectory(worktreeDir, rootDir);
21
+ linkWorktreeNodeModules(worktreeDir, rootDir);
22
+ }
23
+ /**
24
+ * Merges `agent/task-<id>` back into the current branch without ever losing agent work:
25
+ *
26
+ * 1. Uncommitted changes in the worktree are committed on the agent branch first — the
27
+ * verification gatekeeper checked the working tree, so that state is what gets merged.
28
+ * 2. The branch is merged. On failure (e.g. conflicts) the merge is aborted and the
29
+ * worktree and branch are left exactly as they were.
30
+ * 3. Only after a successful merge is the worktree removed and the (now merged) branch
31
+ * deleted with the safe `-d`.
32
+ *
33
+ * Git hooks run normally; a failing hook stops the merge with the work preserved.
34
+ */
35
+ export function mergeAgentWorktree(rootDir, taskId) {
36
+ const worktreeDir = path.join(rootDir, '.worktrees', `task-${taskId}`);
37
+ const branch = `agent/task-${taskId}`;
38
+ const hasWorktree = fs.existsSync(path.join(worktreeDir, '.git'));
39
+ if (!git(rootDir, ['rev-parse', '--verify', '--quiet', `refs/heads/${branch}`]).ok) {
40
+ throw new WorktreeMergeError(`Branch ${branch} does not exist; nothing to merge.`, false);
41
+ }
42
+ let pendingCommit = null;
43
+ if (hasWorktree) {
44
+ // The .ai and node_modules junctions must never be staged, even in repos that do not ignore them.
45
+ safeUnlinkWorktreeNodeModules(worktreeDir);
46
+ safeUnlinkWorktreeAiDirectory(worktreeDir);
47
+ const status = git(worktreeDir, ['status', '--porcelain']);
48
+ if (!status.ok) {
49
+ remount(worktreeDir, rootDir);
50
+ throw new WorktreeMergeError(`Could not read the worktree status: ${status.out}`, true);
51
+ }
52
+ if (status.out) {
53
+ const add = git(worktreeDir, ['add', '-A']);
54
+ const commit = add.ok
55
+ ? git(worktreeDir, ['commit', '-m', `chore(agent): commit uncommitted work from ${taskId}`, '-m', 'Recorded by nativ before merging the verified worktree.'])
56
+ : add;
57
+ if (!commit.ok) {
58
+ remount(worktreeDir, rootDir);
59
+ throw new WorktreeMergeError(`Could not commit the agent's uncommitted changes, so nothing was merged or removed: ${commit.out}`, true);
60
+ }
61
+ pendingCommit = git(worktreeDir, ['rev-parse', 'HEAD']).out || null;
62
+ }
63
+ }
64
+ const merge = git(rootDir, ['merge', branch, '--no-edit']);
65
+ if (!merge.ok) {
66
+ // Leave the main checkout as it was rather than half-merged.
67
+ if (git(rootDir, ['rev-parse', '--verify', '--quiet', 'MERGE_HEAD']).ok)
68
+ git(rootDir, ['merge', '--abort']);
69
+ if (hasWorktree)
70
+ remount(worktreeDir, rootDir);
71
+ const conflict = /CONFLICT|Automatic merge failed/i.test(merge.out);
72
+ throw new WorktreeMergeError(`${conflict ? 'Merge conflict' : 'Merge failed'}; the worktree and ${branch} were kept with all work committed. ${merge.out}`, true);
73
+ }
74
+ let cleanedUp = true;
75
+ if (hasWorktree) {
76
+ // Everything is committed and merged, so a plain remove succeeds; --force only clears ignored build output.
77
+ if (!git(rootDir, ['worktree', 'remove', worktreeDir]).ok) {
78
+ const leftover = git(worktreeDir, ['status', '--porcelain']);
79
+ if (leftover.ok && !leftover.out)
80
+ git(rootDir, ['worktree', 'remove', '--force', worktreeDir]);
81
+ }
82
+ git(rootDir, ['worktree', 'prune']);
83
+ }
84
+ // A directory without git metadata may still hold files nobody committed: report it, never delete it.
85
+ if (fs.existsSync(worktreeDir))
86
+ cleanedUp = false;
87
+ if (!git(rootDir, ['branch', '-d', branch]).ok)
88
+ cleanedUp = false;
89
+ return {
90
+ merged: true,
91
+ committedPendingWork: pendingCommit !== null,
92
+ pendingCommit,
93
+ cleanedUp,
94
+ message: `Merged ${branch}` +
95
+ (pendingCommit ? ' (uncommitted agent work was committed first)' : '') +
96
+ (cleanedUp ? '' : '; the worktree or branch could not be removed and was left in place'),
97
+ };
98
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Multi-Engine Live Data Studio Query and Mutation Engine.
3
+ * Supports PostgreSQL, MySQL, SQLite, MongoDB, and Firebase Firestore.
4
+ *
5
+ * Adheres strictly to Zero-Credential Air-Gap rules:
6
+ * - Direct execution within local process memory.
7
+ * - Raw credentials and connection URLs are never written to disk or returned in responses.
8
+ * - Errors are sanitized to remove credentials and passwords before bubbling up.
9
+ */
10
+ export interface FetchDataOptions {
11
+ page?: number;
12
+ limit?: number;
13
+ sort?: string;
14
+ order?: 'asc' | 'desc';
15
+ search?: string;
16
+ }
17
+ export interface FetchDataResult {
18
+ entity: string;
19
+ entityType: 'table' | 'collection';
20
+ primaryKey: string;
21
+ page: number;
22
+ limit: number;
23
+ totalCount: number;
24
+ totalPages: number;
25
+ rows: Record<string, unknown>[];
26
+ }
27
+ export interface InsertRecordResult {
28
+ success: boolean;
29
+ insertedId: string | number;
30
+ record: Record<string, unknown>;
31
+ }
32
+ export interface UpdateRecordResult {
33
+ success: boolean;
34
+ updatedCount: number;
35
+ record: Record<string, unknown>;
36
+ }
37
+ export interface DeleteRecordResult {
38
+ success: boolean;
39
+ deletedCount: number;
40
+ }
41
+ /** Recursively serializes driver-specific objects (BSON ObjectId, Dates, Buffers, Timestamps) to pure JSON. */
42
+ export declare function serializeValue(val: unknown): unknown;
43
+ export declare function fetchData(url: string, entity: string, options?: FetchDataOptions): Promise<FetchDataResult>;
44
+ export declare function insertRecord(url: string, entity: string, record: Record<string, unknown>): Promise<InsertRecordResult>;
45
+ export declare function updateRecord(url: string, entity: string, primaryKey: string | number, updates: Record<string, unknown>): Promise<UpdateRecordResult>;
46
+ export declare function deleteRecord(url: string, entity: string, primaryKey: string | number): Promise<DeleteRecordResult>;