@tacuchi/agent-workflow-cli 23.0.0 → 24.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 (105) hide show
  1. package/README.md +37 -1
  2. package/dist/adapters/postgres-readonly-tools.js +277 -0
  3. package/dist/adapters/postgres-readonly-tools.js.map +1 -0
  4. package/dist/application/database-mcp-server.js +168 -0
  5. package/dist/application/database-mcp-server.js.map +1 -0
  6. package/dist/application/database-mcp-stdio.js +137 -0
  7. package/dist/application/database-mcp-stdio.js.map +1 -0
  8. package/dist/application/database-tool-catalog.js +226 -0
  9. package/dist/application/database-tool-catalog.js.map +1 -0
  10. package/dist/application/dsn-reader-service.js +1 -1
  11. package/dist/application/lock-service.js +96 -31
  12. package/dist/application/lock-service.js.map +1 -1
  13. package/dist/application/logging/log-events.js +19 -3
  14. package/dist/application/logging/log-events.js.map +1 -1
  15. package/dist/application/logging/logger.js +2 -2
  16. package/dist/application/logging/logger.js.map +1 -1
  17. package/dist/application/mcp-connections-service.js +115 -41
  18. package/dist/application/mcp-connections-service.js.map +1 -1
  19. package/dist/application/mcp-doctor-service.js +98 -54
  20. package/dist/application/mcp-doctor-service.js.map +1 -1
  21. package/dist/application/mcp-entry-classification.js +60 -0
  22. package/dist/application/mcp-entry-classification.js.map +1 -0
  23. package/dist/application/mcp-host-reader.js +102 -86
  24. package/dist/application/mcp-host-reader.js.map +1 -1
  25. package/dist/application/mcp-host-receipt-service.js +399 -0
  26. package/dist/application/mcp-host-receipt-service.js.map +1 -0
  27. package/dist/application/mcp-host-receipt-store.js +122 -0
  28. package/dist/application/mcp-host-receipt-store.js.map +1 -0
  29. package/dist/application/mcp-host-receipts.js +28 -0
  30. package/dist/application/mcp-host-receipts.js.map +1 -0
  31. package/dist/application/mcp-host-writer.js +209 -38
  32. package/dist/application/mcp-host-writer.js.map +1 -1
  33. package/dist/application/mcp-launch-probe-service.js +142 -0
  34. package/dist/application/mcp-launch-probe-service.js.map +1 -0
  35. package/dist/application/mcp-migration-service.js +351 -0
  36. package/dist/application/mcp-migration-service.js.map +1 -0
  37. package/dist/application/mcp-native-host-check-service.js +154 -0
  38. package/dist/application/mcp-native-host-check-service.js.map +1 -0
  39. package/dist/application/mcp-receipt-registration-service.js +105 -0
  40. package/dist/application/mcp-receipt-registration-service.js.map +1 -0
  41. package/dist/application/mcp-receipt-removal-service.js +62 -0
  42. package/dist/application/mcp-receipt-removal-service.js.map +1 -0
  43. package/dist/application/mcp-remove-service.js +83 -24
  44. package/dist/application/mcp-remove-service.js.map +1 -1
  45. package/dist/application/mcp-scope-common.js +1 -1
  46. package/dist/application/mcp-scope-common.js.map +1 -1
  47. package/dist/application/mcp-setup-service.js +59 -24
  48. package/dist/application/mcp-setup-service.js.map +1 -1
  49. package/dist/application/mcp-stdio-probe.js +526 -0
  50. package/dist/application/mcp-stdio-probe.js.map +1 -0
  51. package/dist/application/mcp-test-connection-service.js +23 -50
  52. package/dist/application/mcp-test-connection-service.js.map +1 -1
  53. package/dist/application/self/host-states.js.map +1 -1
  54. package/dist/application/self/install-skill.js +4 -34
  55. package/dist/application/self/install-skill.js.map +1 -1
  56. package/dist/application/self/mcp-config.js +369 -59
  57. package/dist/application/self/mcp-config.js.map +1 -1
  58. package/dist/application/self/mcp-via-state.js +9 -6
  59. package/dist/application/self/mcp-via-state.js.map +1 -1
  60. package/dist/application/self/uninstall-skill.js +3 -18
  61. package/dist/application/self/uninstall-skill.js.map +1 -1
  62. package/dist/application/self/uninstall.js +4 -23
  63. package/dist/application/self/uninstall.js.map +1 -1
  64. package/dist/application/workspace-init-service.js +4 -6
  65. package/dist/application/workspace-init-service.js.map +1 -1
  66. package/dist/cli/commands/index.js +2 -0
  67. package/dist/cli/commands/index.js.map +1 -1
  68. package/dist/cli/commands/mcp.js +642 -55
  69. package/dist/cli/commands/mcp.js.map +1 -1
  70. package/dist/cli/commands/tool.js +141 -0
  71. package/dist/cli/commands/tool.js.map +1 -0
  72. package/dist/cli/help-groups.js +1 -1
  73. package/dist/cli/help-groups.js.map +1 -1
  74. package/dist/cli/main.js +189 -57
  75. package/dist/cli/main.js.map +1 -1
  76. package/dist/cli/parser.js +5 -1
  77. package/dist/cli/parser.js.map +1 -1
  78. package/dist/cli/registry.js.map +1 -1
  79. package/dist/cli/render.js +15 -2
  80. package/dist/cli/render.js.map +1 -1
  81. package/dist/cli/tui/components/host-admin-section.js +2 -46
  82. package/dist/cli/tui/components/host-admin-section.js.map +1 -1
  83. package/dist/cli/tui/tabs/mcp-tab-helpers.js +71 -0
  84. package/dist/cli/tui/tabs/mcp-tab-helpers.js.map +1 -1
  85. package/dist/cli/tui/tabs/mcp-tab.js +101 -42
  86. package/dist/cli/tui/tabs/mcp-tab.js.map +1 -1
  87. package/dist/domain/database-tools.js +445 -0
  88. package/dist/domain/database-tools.js.map +1 -0
  89. package/dist/domain/flow/authority.js +4 -0
  90. package/dist/domain/flow/authority.js.map +1 -1
  91. package/dist/domain/mcp-entry.js +131 -17
  92. package/dist/domain/mcp-entry.js.map +1 -1
  93. package/dist/domain/postgres-object-search.js +320 -0
  94. package/dist/domain/postgres-object-search.js.map +1 -0
  95. package/dist/domain/redaction.js +47 -0
  96. package/dist/domain/redaction.js.map +1 -0
  97. package/dist/domain/workline-mcp-entry.js +6 -9
  98. package/dist/domain/workline-mcp-entry.js.map +1 -1
  99. package/dist/ports/postgres-tools.js +10 -0
  100. package/dist/ports/postgres-tools.js.map +1 -0
  101. package/package.json +5 -1
  102. package/dist/application/mcp-dbhub-launcher.js +0 -216
  103. package/dist/application/mcp-dbhub-launcher.js.map +0 -1
  104. package/dist/application/self/mcp-offer.js +0 -96
  105. package/dist/application/self/mcp-offer.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-mcp-stdio.js","sourceRoot":"","sources":["../../src/application/database-mcp-stdio.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,226 @@
1
+ import { DATABASE_TOOL_DESCRIPTORS, MAX_TOOL_RESULT_BYTES, isDatabaseToolName, parseDatabaseToolInput, toolFailure, toolSuccess, validateReadOnlySql, } from "../domain/database-tools.js";
2
+ import { buildPostgresObjectSearchQuery, normalizePostgresObjectSearchRows, } from "../domain/postgres-object-search.js";
3
+ import { PostgresToolError, } from "../ports/postgres-tools.js";
4
+ import { readDsnFile } from "./dsn-reader-service.js";
5
+ import { resolveMcpConnectionSelection, } from "./mcp-connections-service.js";
6
+ /**
7
+ * The deep module for database tools. Its small interface is shared by direct
8
+ * CLI and MCP adapters; connection lookup, validation, policy, handler choice
9
+ * and response encoding stay local instead of drifting across transports.
10
+ */
11
+ export class DatabaseToolCatalog {
12
+ deps;
13
+ constructor(deps) {
14
+ this.deps = deps;
15
+ }
16
+ list(connection) {
17
+ const selected = this.selectConnection(connection);
18
+ if (!selected.ok)
19
+ return { payload: sanitizeSelectionFailure(selected.response), exitCode: 2 };
20
+ return { payload: { tools: DATABASE_TOOL_DESCRIPTORS }, exitCode: 0 };
21
+ }
22
+ async call(call) {
23
+ const prepared = this.prepareCall(call);
24
+ if (!prepared.ok)
25
+ return prepared.outcome;
26
+ if (prepared.value.tool === "execute_sql")
27
+ return await this.executeSql(prepared.value);
28
+ return await this.searchObjects(prepared.value);
29
+ }
30
+ prepareCall(call) {
31
+ if (!isDatabaseToolName(call.tool))
32
+ return {
33
+ ok: false,
34
+ outcome: failureOutcome("TOOL_NOT_FOUND", "La tool solicitada no existe.", 2),
35
+ };
36
+ const selected = this.selectConnection(call.connection);
37
+ if (!selected.ok) {
38
+ return {
39
+ ok: false,
40
+ outcome: { response: sanitizeSelectionFailure(selected.response), exitCode: 2 },
41
+ };
42
+ }
43
+ const dsn = this.resolveDsn(selected.connection);
44
+ if (!dsn.ok)
45
+ return { ok: false, outcome: { response: dsn.response, exitCode: 2 } };
46
+ const parsed = parseDatabaseToolInput(call.tool, call.input);
47
+ if (!parsed.ok)
48
+ return { ok: false, outcome: failureFromResponse(parsed.response, 2) };
49
+ if (call.tool === "execute_sql") {
50
+ return {
51
+ ok: true,
52
+ value: {
53
+ tool: call.tool,
54
+ input: parsed.value,
55
+ dsn: dsn.value,
56
+ ...(call.signal === undefined ? {} : { signal: call.signal }),
57
+ },
58
+ };
59
+ }
60
+ return {
61
+ ok: true,
62
+ value: {
63
+ tool: call.tool,
64
+ input: parsed.value,
65
+ dsn: dsn.value,
66
+ ...(call.signal === undefined ? {} : { signal: call.signal }),
67
+ },
68
+ };
69
+ }
70
+ async executeSql(call) {
71
+ const policy = validateReadOnlySql(call.input.sql);
72
+ if (!policy.ok) {
73
+ return failureFromResponse(policy.response, policy.response.code === "INVALID_SQL" ? 2 : 1);
74
+ }
75
+ return await this.runDatabaseOperation(async () => {
76
+ const result = call.signal === undefined
77
+ ? await this.deps.postgres.execute(call.input.sql, call.dsn)
78
+ : await this.deps.postgres.execute(call.input.sql, call.dsn, { signal: call.signal });
79
+ return this.enforceResultLimit(toolSuccess({
80
+ statements: [
81
+ {
82
+ sql: call.input.sql,
83
+ rows: result.rows,
84
+ count: result.rows.length,
85
+ ...(result.truncated ? { truncated: true } : {}),
86
+ },
87
+ ],
88
+ source_id: "default",
89
+ }));
90
+ });
91
+ }
92
+ async searchObjects(call) {
93
+ // Ask for one extra row so `truncated` means an observed row was
94
+ // omitted, rather than a guess based on a LIMIT boundary.
95
+ const query = buildPostgresObjectSearchQuery({ ...call.input, limit: call.input.limit + 1 });
96
+ return await this.runDatabaseOperation(async () => {
97
+ const result = call.signal === undefined
98
+ ? await this.deps.postgres.query(query.sql, query.values, call.dsn)
99
+ : await this.deps.postgres.query(query.sql, query.values, call.dsn, {
100
+ signal: call.signal,
101
+ });
102
+ const rows = normalizePostgresObjectSearchRows(call.input, result.rows.slice(0, call.input.limit));
103
+ return this.enforceResultLimit(toolSuccess({
104
+ object_type: call.input.object_type,
105
+ pattern: call.input.pattern,
106
+ ...(call.input.schema === undefined ? {} : { schema: call.input.schema }),
107
+ ...(call.input.table === undefined ? {} : { table: call.input.table }),
108
+ detail_level: call.input.detail_level,
109
+ count: rows.length,
110
+ results: rows,
111
+ truncated: result.truncated || result.rows.length > call.input.limit,
112
+ }));
113
+ });
114
+ }
115
+ async runDatabaseOperation(operation) {
116
+ try {
117
+ return await operation();
118
+ }
119
+ catch (error) {
120
+ if (error instanceof PostgresToolError) {
121
+ return failureOutcome(error.code, error.message, databaseErrorExitCode(error.code));
122
+ }
123
+ return failureOutcome("DATABASE_QUERY_FAILED", "La base de datos no pudo completar la operación.", 1);
124
+ }
125
+ }
126
+ async inspectRole(connection) {
127
+ const selected = this.selectConnection(connection);
128
+ if (!selected.ok)
129
+ return { inspection: selected.response, exitCode: 2 };
130
+ const dsn = this.resolveDsn(selected.connection);
131
+ if (!dsn.ok)
132
+ return { inspection: dsn.response, exitCode: 2 };
133
+ try {
134
+ return { inspection: await this.deps.postgres.inspectRole(dsn.value), exitCode: 0 };
135
+ }
136
+ catch (error) {
137
+ if (error instanceof PostgresToolError) {
138
+ return {
139
+ inspection: toolFailure(error.code, error.message),
140
+ exitCode: databaseErrorExitCode(error.code),
141
+ };
142
+ }
143
+ return {
144
+ inspection: toolFailure("DATABASE_QUERY_FAILED", "No se pudo verificar el rol PostgreSQL."),
145
+ exitCode: 1,
146
+ };
147
+ }
148
+ }
149
+ selectConnection(connection) {
150
+ let selection;
151
+ try {
152
+ selection = resolveMcpConnectionSelection(this.deps.paths, { instance: connection });
153
+ }
154
+ catch {
155
+ return {
156
+ ok: false,
157
+ response: toolFailure("MCP_CONNECTION_INVALID", "No se pudo resolver la conexión solicitada."),
158
+ };
159
+ }
160
+ if (!selection.ok)
161
+ return { ok: false, response: toolFailure(selection.code, selection.message) };
162
+ const selected = selection.connections[0];
163
+ if (selected === undefined) {
164
+ return {
165
+ ok: false,
166
+ response: toolFailure("MCP_CONNECTION_NOT_REGISTERED", "La conexión no está registrada."),
167
+ };
168
+ }
169
+ if (selected.provider !== "postgres") {
170
+ return {
171
+ ok: false,
172
+ response: toolFailure("TOOL_PROVIDER_UNSUPPORTED", "Esta tool sólo admite conexiones PostgreSQL."),
173
+ };
174
+ }
175
+ return { ok: true, connection: selected };
176
+ }
177
+ resolveDsn(connection) {
178
+ const environment = this.deps.env.get(connection.dsnVar);
179
+ if (environment !== undefined && environment.length > 0)
180
+ return { ok: true, value: environment };
181
+ try {
182
+ const file = readDsnFile(this.deps.paths).values[connection.dsnVar];
183
+ if (file !== undefined && file.length > 0)
184
+ return { ok: true, value: file };
185
+ }
186
+ catch {
187
+ return {
188
+ ok: false,
189
+ response: toolFailure("DATABASE_CONNECTION_INVALID", "No se pudo leer la configuración de conexión."),
190
+ };
191
+ }
192
+ return {
193
+ ok: false,
194
+ response: toolFailure("DATABASE_CONNECTION_MISSING", `La conexión '${connection.name}' no tiene un DSN disponible.`),
195
+ };
196
+ }
197
+ enforceResultLimit(response) {
198
+ try {
199
+ const bytes = new TextEncoder().encode(JSON.stringify(response)).byteLength;
200
+ if (bytes > MAX_TOOL_RESULT_BYTES) {
201
+ return failureOutcome("RESULT_TOO_LARGE", "El resultado serializado supera 4 MiB.", 1);
202
+ }
203
+ return { response, exitCode: 0 };
204
+ }
205
+ catch {
206
+ return failureOutcome("RESULT_TOO_LARGE", "El resultado no se puede serializar de forma segura.", 1);
207
+ }
208
+ }
209
+ }
210
+ function failureOutcome(code, message, exitCode) {
211
+ return { response: toolFailure(code, message), exitCode };
212
+ }
213
+ function failureFromResponse(response, exitCode) {
214
+ return { response, exitCode };
215
+ }
216
+ function databaseErrorExitCode(code) {
217
+ return code === "DATABASE_CONNECTION_FAILED" ||
218
+ code === "DATABASE_CONNECTION_INVALID" ||
219
+ code === "INVALID_SQL"
220
+ ? 2
221
+ : 1;
222
+ }
223
+ function sanitizeSelectionFailure(response) {
224
+ return toolFailure(response.code, "No se pudo resolver la conexión solicitada.");
225
+ }
226
+ //# sourceMappingURL=database-tool-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database-tool-catalog.js","sourceRoot":"","sources":["../../src/application/database-tool-catalog.ts"],"names":[],"mappings":"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"}
@@ -25,7 +25,7 @@ export function dsnKeyForInstance(instance) {
25
25
  return `DB_${normalizeMcpInstance(instance).replace(/-/g, "_").toUpperCase()}_DSN`;
26
26
  }
27
27
  /**
28
- * Single resolution path shared by the dbhub launcher and the connection
28
+ * Single resolution path shared by the database tool catalog and the connection
29
29
  * tester. The caller supplies the exact variable registered for the connection;
30
30
  * the environment wins over the local dsn.env file for that one name only.
31
31
  *
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import { dirname } from "node:path";
2
3
  export class LockBusyError extends Error {
3
4
  lockPath;
@@ -10,20 +11,70 @@ export class LockBusyError extends Error {
10
11
  }
11
12
  }
12
13
  export const DEFAULT_LOCK_TTL_MS = 5 * 60 * 1000;
13
- const RELEASED_MARKER = "";
14
14
  const MAX_CLAIM_RETRIES = 3;
15
15
  const DEFAULT_WAIT_STEP_MS = 15;
16
- export async function acquireLock(lockPath, fs, options = {}) {
17
- const ttlMs = options.ttlMs ?? DEFAULT_LOCK_TTL_MS;
18
- const pid = options.pid ?? process.pid;
16
+ /**
17
+ * Serializes the small read/create/cleanup window for callers in this Node
18
+ * process. The filesystem lock remains the inter-process arbiter for live
19
+ * holders; this queue closes the same-process window where multiple async
20
+ * callers observed and cleared the same released marker.
21
+ */
22
+ const localLockTails = new Map();
23
+ async function underLocalLock(path, operation) {
24
+ const previous = localLockTails.get(path) ?? Promise.resolve();
25
+ let release;
26
+ const current = new Promise((resolve) => {
27
+ release = resolve;
28
+ });
29
+ const tail = previous.then(() => current);
30
+ localLockTails.set(path, tail);
31
+ await previous;
32
+ try {
33
+ return await operation();
34
+ }
35
+ finally {
36
+ release?.();
37
+ if (localLockTails.get(path) === tail)
38
+ localLockTails.delete(path);
39
+ }
40
+ }
41
+ async function tryAcquireStep(fs, lockPath, serialized, nowMs, ttlMs) {
42
+ return await underLocalLock(lockPath, async () => {
43
+ const result = await fs.writeTextExclusive(lockPath, serialized);
44
+ if (result.created)
45
+ return { kind: "acquired" };
46
+ const slot = await readSlot(fs, lockPath, nowMs, ttlMs);
47
+ if (slot.held)
48
+ return { kind: "held", holder: slot.holder };
49
+ // A missing path is already available for a fresh exclusive create. Do not
50
+ // remove it: another process can have acquired it between the failed create
51
+ // and the read. Free legacy/stale contents are cleared while the local queue
52
+ // owns the inspection, then the next loop creates afresh.
53
+ if (slot.present)
54
+ await fs.remove(lockPath);
55
+ return { kind: "retry", lastSeen: slot.holder };
56
+ });
57
+ }
58
+ function lockRequest(options) {
19
59
  const now = options.now ?? Date.now;
20
60
  const ts = now();
21
- const waitMs = options.waitMs ?? 0;
22
- const waitStepMs = options.waitStepMs ?? DEFAULT_WAIT_STEP_MS;
23
- const deadline = ts + waitMs;
24
- await fs.mkdirp(dirname(lockPath));
25
- const content = { pid, ts: new Date(ts).toISOString() };
26
- const serialized = JSON.stringify(content);
61
+ return {
62
+ ttlMs: options.ttlMs ?? DEFAULT_LOCK_TTL_MS,
63
+ pid: options.pid ?? process.pid,
64
+ now,
65
+ ts,
66
+ deadline: ts + (options.waitMs ?? 0),
67
+ waitStepMs: options.waitStepMs ?? DEFAULT_WAIT_STEP_MS,
68
+ };
69
+ }
70
+ function serializedLock(request) {
71
+ return JSON.stringify({
72
+ pid: request.pid,
73
+ ts: new Date(request.ts).toISOString(),
74
+ token: randomUUID(),
75
+ });
76
+ }
77
+ async function waitForLock(fs, lockPath, serialized, request) {
27
78
  let lastSeen = null;
28
79
  // Two budgets, and conflating them breaks either one. `steals` bounds how often
29
80
  // a competing claimer may take the slot we just cleared — the fail-fast caller's
@@ -33,26 +84,31 @@ export async function acquireLock(lockPath, fs, options = {}) {
33
84
  // each and all report "busy" over a lock nobody holds.
34
85
  let steals = 0;
35
86
  while (steals < MAX_CLAIM_RETRIES) {
36
- const result = await fs.writeTextExclusive(lockPath, serialized);
37
- if (result.created) {
38
- return makeHandle(fs, lockPath, pid, ts, options.removeOnRelease === true);
87
+ const step = await tryAcquireStep(fs, lockPath, serialized, request.now(), request.ttlMs);
88
+ if (step.kind === "acquired") {
89
+ return makeHandle(fs, lockPath, request.pid, request.ts, serialized);
39
90
  }
40
- const slot = await readSlot(fs, lockPath, now(), ttlMs);
41
- if (slot.holder !== null)
42
- lastSeen = slot.holder;
43
- if (slot.held) {
44
- if (await keepWaiting(now, deadline, waitStepMs))
91
+ if (step.kind === "held") {
92
+ if (await keepWaiting(request.now, request.deadline, request.waitStepMs))
45
93
  continue;
46
- throw new LockBusyError(lockPath, slot.holder);
94
+ throw new LockBusyError(lockPath, step.holder);
47
95
  }
48
- // Stale, release marker, corrupted or already gone: clear it and race again.
49
- await fs.remove(lockPath);
50
- if (await keepWaiting(now, deadline, 0))
96
+ if (step.lastSeen !== null)
97
+ lastSeen = step.lastSeen;
98
+ // Stale, release marker, corrupt or already gone: the local section either
99
+ // cleared the old content or observed an already-free path. Yield before
100
+ // retrying so a just-released in-process holder cannot be starved.
101
+ if (await keepWaiting(request.now, request.deadline, 0))
51
102
  continue;
52
103
  steals++;
53
104
  }
54
105
  // Exceeded retries — another claimer kept stealing the slot. Surface as busy.
55
- throw new LockBusyError(lockPath, lastSeen ?? { pid: 0, ts: new Date(ts).toISOString() });
106
+ throw new LockBusyError(lockPath, lastSeen ?? { pid: 0, ts: new Date(request.ts).toISOString() });
107
+ }
108
+ export async function acquireLock(lockPath, fs, options = {}) {
109
+ const request = lockRequest(options);
110
+ await fs.mkdirp(dirname(lockPath));
111
+ return await waitForLock(fs, lockPath, serializedLock(request), request);
56
112
  }
57
113
  async function readSlot(fs, lockPath, nowMs, ttlMs) {
58
114
  let raw;
@@ -61,13 +117,13 @@ async function readSlot(fs, lockPath, nowMs, ttlMs) {
61
117
  }
62
118
  catch {
63
119
  // Removed between the EEXIST and this read: the slot is free again.
64
- return { held: false, holder: null };
120
+ return { held: false, holder: null, present: false };
65
121
  }
66
122
  const existing = parseLock(raw);
67
123
  if (existing !== null && !isExpired(existing, nowMs, ttlMs)) {
68
124
  return { held: true, holder: existing };
69
125
  }
70
- return { held: false, holder: existing };
126
+ return { held: false, holder: existing, present: true };
71
127
  }
72
128
  /**
73
129
  * Whether there is still wait budget, sleeping `stepMs` before the next attempt.
@@ -85,7 +141,7 @@ async function keepWaiting(now, deadline, stepMs) {
85
141
  function sleep(ms) {
86
142
  return new Promise((resolve) => setTimeout(resolve, ms));
87
143
  }
88
- function makeHandle(fs, lockPath, pid, ts, removeOnRelease) {
144
+ function makeHandle(fs, lockPath, pid, ts, serialized) {
89
145
  let released = false;
90
146
  return {
91
147
  path: lockPath,
@@ -96,13 +152,22 @@ function makeHandle(fs, lockPath, pid, ts, removeOnRelease) {
96
152
  return;
97
153
  released = true;
98
154
  try {
99
- if (removeOnRelease)
100
- await fs.remove(lockPath);
101
- else
102
- await fs.writeText(lockPath, RELEASED_MARKER);
155
+ await underLocalLock(lockPath, async () => {
156
+ let current;
157
+ try {
158
+ current = await fs.readText(lockPath);
159
+ }
160
+ catch {
161
+ return;
162
+ }
163
+ // A stale holder may wake up after a new process acquired the same
164
+ // pathname. It can only release the bytes it created itself.
165
+ if (current === serialized)
166
+ await fs.remove(lockPath);
167
+ });
103
168
  }
104
169
  catch {
105
- // best-effort: stale lock will auto-expire via ttl
170
+ // Best effort: a stale lock can still be recovered after its TTL.
106
171
  }
107
172
  },
108
173
  };
@@ -1 +1 @@
1
- {"version":3,"file":"lock-service.js","sourceRoot":"","sources":["../../src/application/lock-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lock-service.js","sourceRoot":"","sources":["../../src/application/lock-service.ts"],"names":[],"mappings":"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"}
@@ -4,17 +4,26 @@
4
4
  * (see `redactSecrets`), so this stays a faithful reconstruction.
5
5
  */
6
6
  export function formatCommandInvocation(parsed) {
7
+ if (parsed.command === "tool")
8
+ return "tool request --connection=<redacted> --input-json=<redacted>";
9
+ // MCP descriptors and probes may receive arbitrary flags before validation.
10
+ // Do not let an accidental libpq DSN, SQL, JSON payload, or host diagnostic
11
+ // become telemetry just because it was attached to an otherwise valid mcp
12
+ // command. The operation name is sufficient for an operational audit trail.
13
+ if (parsed.command === "mcp")
14
+ return "mcp request --arguments=<redacted>";
7
15
  const parts = [];
8
16
  if (parsed.command)
9
17
  parts.push(parsed.command);
10
18
  parts.push(...parsed.rest);
11
19
  for (const flag of parsed.flags)
12
20
  parts.push(`--${flag}`);
13
- for (const [key, value] of parsed.values)
14
- parts.push(`--${key}=${value}`);
21
+ for (const [key, value] of parsed.values) {
22
+ parts.push(`--${key}=${redactedInvocationValue(key, value)}`);
23
+ }
15
24
  for (const [key, values] of parsed.valuesMulti) {
16
25
  for (const value of values)
17
- parts.push(`--${key}=${value}`);
26
+ parts.push(`--${key}=${redactedInvocationValue(key, value)}`);
18
27
  }
19
28
  return parts.join(" ");
20
29
  }
@@ -24,9 +33,16 @@ export function formatCommandOutcome(command, exitCode) {
24
33
  }
25
34
  /** `<command> → error: <message>` for a thrown dispatch. */
26
35
  export function formatCommandError(command, err) {
36
+ if (command === "tool" || command === "mcp")
37
+ return `${command} → error: solicitud MCP/DB falló`;
27
38
  const message = err instanceof Error ? err.message : String(err);
28
39
  return `${command} → error: ${message}`;
29
40
  }
41
+ function redactedInvocationValue(key, value) {
42
+ // SQL and arbitrary tool arguments may contain personal or proprietary data.
43
+ // They are a direct request payload, never operational telemetry.
44
+ return key === "input-json" ? "<redacted>" : value;
45
+ }
30
46
  /**
31
47
  * `tui: <action>` (optionally `→ <outcome>` or `→ <outcome>: <detail>`) for a
32
48
  * TUI-originated event in the operational log. Mirrors the `<command> → …` shape
@@ -1 +1 @@
1
- {"version":3,"file":"log-events.js","sourceRoot":"","sources":["../../../src/application/logging/log-events.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAkB;IACxD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;IAC1E,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QAC/C,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,QAAgB;IACpE,OAAO,GAAG,OAAO,WAAW,QAAQ,EAAE,CAAC;AACzC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,GAAY;IAC9D,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,GAAG,OAAO,aAAa,OAAO,EAAE,CAAC;AAC1C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAAgB,EAAE,MAAe;IAC9E,IAAI,CAAC,OAAO;QAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;IACtC,OAAO,QAAQ,MAAM,MAAM,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AAC1E,CAAC"}
1
+ {"version":3,"file":"log-events.js","sourceRoot":"","sources":["../../../src/application/logging/log-events.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAkB;IACxD,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM;QAC3B,OAAO,8DAA8D,CAAC;IACxE,4EAA4E;IAC5E,4EAA4E;IAC5E,0EAA0E;IAC1E,4EAA4E;IAC5E,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK;QAAE,OAAO,oCAAoC,CAAC;IAC1E,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,CAAC,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/C,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACzD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACzC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,uBAAuB,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QAC/C,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,uBAAuB,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,QAAgB;IACpE,OAAO,GAAG,OAAO,WAAW,QAAQ,EAAE,CAAC;AACzC,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,GAAY;IAC9D,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,KAAK;QAAE,OAAO,GAAG,OAAO,kCAAkC,CAAC;IACjG,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,GAAG,OAAO,aAAa,OAAO,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,uBAAuB,CAAC,GAAW,EAAE,KAAa;IACzD,6EAA6E;IAC7E,kEAAkE;IAClE,OAAO,GAAG,KAAK,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;AACrD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAAgB,EAAE,MAAe;IAC9E,IAAI,CAAC,OAAO;QAAE,OAAO,QAAQ,MAAM,EAAE,CAAC;IACtC,OAAO,QAAQ,MAAM,MAAM,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AAC1E,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { redactSensitiveText } from "../../domain/redaction.js";
1
2
  /**
2
3
  * Operational logger: appends one line per event to the GLOBAL, user-level daily
3
4
  * log (`~/.${ns}/logs/agent-workflow-YYYY-MM-DD.log`), the same file regardless of
@@ -43,7 +44,6 @@ export class Logger {
43
44
  * conservative: it targets named secret flags + Bearer tokens.
44
45
  */
45
46
  export function redactSecrets(text) {
46
- const SECRET_FLAG = /(--?(?:token|secret|password|passwd|pwd|api[-_]?key|key|auth)[=\s]+)(\S+)/gi;
47
- return text.replace(SECRET_FLAG, "$1***").replace(/\bBearer\s+\S+/gi, "Bearer ***");
47
+ return redactSensitiveText(text);
48
48
  }
49
49
  //# sourceMappingURL=logger.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/application/logging/logger.ts"],"names":[],"mappings":"AAcA;;;;;GAKG;AACH,MAAM,OAAO,MAAM;IACA,EAAE,CAAiB;IACnB,KAAK,CAAe;IACpB,GAAG,CAAa;IAChB,OAAO,CAAU;IAElC,YAAY,IAAgB;QAC1B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;IACtC,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,OAAe;QACnB,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAe,EAAE,OAAe;QACxC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;QACtF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,WAAW,GAAG,6EAA6E,CAAC;IAClG,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;AACtF,CAAC"}
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/application/logging/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAehE;;;;;GAKG;AACH,MAAM,OAAO,MAAM;IACA,EAAE,CAAiB;IACnB,KAAK,CAAe;IACpB,GAAG,CAAa;IAChB,OAAO,CAAU;IAElC,YAAY,IAAgB;QAC1B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC;IACtC,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,KAAK,CAAC,OAAe;QACnB,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,KAAe,EAAE,OAAe;QACxC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO;QAC1B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;QACtF,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QAClE,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;IACH,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}