@tacuchi/agent-workflow-cli 25.1.2 → 25.2.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 (92) hide show
  1. package/README.md +2 -1
  2. package/dist/adapters/node-process.js +35 -0
  3. package/dist/adapters/node-process.js.map +1 -1
  4. package/dist/application/amend-service.js +393 -0
  5. package/dist/application/amend-service.js.map +1 -0
  6. package/dist/application/doctor/actions.js +158 -0
  7. package/dist/application/doctor/actions.js.map +1 -0
  8. package/dist/application/doctor/apply.js +399 -0
  9. package/dist/application/doctor/apply.js.map +1 -0
  10. package/dist/application/doctor/auth-dsn.js +143 -0
  11. package/dist/application/doctor/auth-dsn.js.map +1 -0
  12. package/dist/application/doctor/auth-flow.js +28 -0
  13. package/dist/application/doctor/auth-flow.js.map +1 -0
  14. package/dist/application/doctor/auth-registry.js +12 -0
  15. package/dist/application/doctor/auth-registry.js.map +1 -0
  16. package/dist/application/doctor/hosts.js +41 -0
  17. package/dist/application/doctor/hosts.js.map +1 -0
  18. package/dist/application/doctor/native-host-state.js +211 -0
  19. package/dist/application/doctor/native-host-state.js.map +1 -0
  20. package/dist/application/doctor/prepare.js +262 -0
  21. package/dist/application/doctor/prepare.js.map +1 -0
  22. package/dist/application/doctor/provider-installation.js +124 -0
  23. package/dist/application/doctor/provider-installation.js.map +1 -0
  24. package/dist/application/doctor/provider-mcps.js +650 -0
  25. package/dist/application/doctor/provider-mcps.js.map +1 -0
  26. package/dist/application/doctor/provider-plugins-hooks.js +112 -0
  27. package/dist/application/doctor/provider-plugins-hooks.js.map +1 -0
  28. package/dist/application/doctor/provider-skills.js +212 -0
  29. package/dist/application/doctor/provider-skills.js.map +1 -0
  30. package/dist/application/doctor/provider-tools-auth.js +201 -0
  31. package/dist/application/doctor/provider-tools-auth.js.map +1 -0
  32. package/dist/application/doctor/provider-visibility.js +149 -0
  33. package/dist/application/doctor/provider-visibility.js.map +1 -0
  34. package/dist/application/doctor/repair-runner.js +169 -0
  35. package/dist/application/doctor/repair-runner.js.map +1 -0
  36. package/dist/application/doctor/report.js +155 -0
  37. package/dist/application/doctor/report.js.map +1 -0
  38. package/dist/application/doctor/types.js +5 -0
  39. package/dist/application/doctor/types.js.map +1 -0
  40. package/dist/application/flow/advance.js +62 -9
  41. package/dist/application/flow/advance.js.map +1 -1
  42. package/dist/application/flow/flow-service.js +18 -7
  43. package/dist/application/flow/flow-service.js.map +1 -1
  44. package/dist/application/flow/run-projection.js +6 -1
  45. package/dist/application/flow/run-projection.js.map +1 -1
  46. package/dist/application/flow/submit.js +143 -3
  47. package/dist/application/flow/submit.js.map +1 -1
  48. package/dist/application/mcp-doctor-service.js +1 -1
  49. package/dist/application/mcp-doctor-service.js.map +1 -1
  50. package/dist/application/mcp-host-reader.js +134 -26
  51. package/dist/application/mcp-host-reader.js.map +1 -1
  52. package/dist/application/mcp-host-receipt-service.js +9 -7
  53. package/dist/application/mcp-host-receipt-service.js.map +1 -1
  54. package/dist/application/self/install-skill.js +10 -2
  55. package/dist/application/self/install-skill.js.map +1 -1
  56. package/dist/application/self/mcp-config.js +1 -1
  57. package/dist/application/self/mcp-config.js.map +1 -1
  58. package/dist/application/session-narrative.js +15 -0
  59. package/dist/application/session-narrative.js.map +1 -1
  60. package/dist/application/source-boundary-policy.js +87 -6
  61. package/dist/application/source-boundary-policy.js.map +1 -1
  62. package/dist/cli/commands/amend.js +122 -0
  63. package/dist/cli/commands/amend.js.map +1 -0
  64. package/dist/cli/commands/doctor.js +300 -0
  65. package/dist/cli/commands/doctor.js.map +1 -0
  66. package/dist/cli/commands/index.js +4 -0
  67. package/dist/cli/commands/index.js.map +1 -1
  68. package/dist/cli/dispatch-plan.js +47 -0
  69. package/dist/cli/dispatch-plan.js.map +1 -0
  70. package/dist/cli/help-groups.js +8 -0
  71. package/dist/cli/help-groups.js.map +1 -1
  72. package/dist/cli/main.js +54 -10
  73. package/dist/cli/main.js.map +1 -1
  74. package/dist/cli/parser.js +20 -0
  75. package/dist/cli/parser.js.map +1 -1
  76. package/dist/domain/doctor/auth.js +65 -0
  77. package/dist/domain/doctor/auth.js.map +1 -0
  78. package/dist/domain/doctor/model.js +82 -0
  79. package/dist/domain/doctor/model.js.map +1 -0
  80. package/dist/domain/doctor/operations.js +114 -0
  81. package/dist/domain/doctor/operations.js.map +1 -0
  82. package/dist/domain/flow/authority.js +8 -0
  83. package/dist/domain/flow/authority.js.map +1 -1
  84. package/dist/domain/flow/run-state.js +181 -25
  85. package/dist/domain/flow/run-state.js.map +1 -1
  86. package/dist/domain/redaction.js +40 -0
  87. package/dist/domain/redaction.js.map +1 -1
  88. package/package.json +1 -1
  89. package/skills/w/SKILL.md +2 -1
  90. package/skills/w/commands/README.md +2 -1
  91. package/skills/w/commands/doctor.md +31 -0
  92. package/skills/w/context/MANIFEST.json +4 -0
@@ -0,0 +1,143 @@
1
+ import { readMcpConnections } from "../mcp-connections-service.js";
2
+ import { testMcpConnection } from "../mcp-test-connection-service.js";
3
+ import { buildEnvHelp, isDsnVisible } from "../self/mcp-config.js";
4
+ /** El prefijo que hace único el id de un sujeto de este proveedor en todo el registro. */
5
+ const SUBJECT_PREFIX = "env:";
6
+ export const dsnAuthProvider = {
7
+ id: "dsn",
8
+ subjects(ctx) {
9
+ return readMcpConnections(ctx.paths, ctx.env).map((connection) => ({
10
+ id: `${SUBJECT_PREFIX}${connection.name}`,
11
+ label: connection.dsnVar,
12
+ locator: ctx.paths.userDsnFile(),
13
+ }));
14
+ },
15
+ async check(subject, ctx) {
16
+ const visible = isDsnVisible(ctx, subject.label);
17
+ return {
18
+ state: visible ? "present" : "absent",
19
+ // La evidencia dice PRESENTE o AUSENTE y se detiene ahí. Leer el valor
20
+ // para describirlo dejaría al informe a un defecto de redacción de
21
+ // publicarlo.
22
+ //
23
+ // El nombre de la variable va SIEMPRE entre paréntesis, y eso es
24
+ // load-bearing: el redactor lee `<algo>_DSN` seguido de `=`, `:` o un
25
+ // espacio como una asignación y reemplaza lo que viene después. Nombrar la
26
+ // variable es exactamente lo que este hallazgo le debe a la persona, así
27
+ // que el único lugar donde aparece tiene que ser una forma que el redactor
28
+ // no pueda leer como un valor: un paréntesis de cierre no es un separador,
29
+ // así que `(DB_X_DSN)` sobrevive y `DB_X_DSN: presente` no.
30
+ evidence: [`variable de entorno (${subject.label}): ${visible ? "presente" : "ausente"}`],
31
+ };
32
+ },
33
+ /**
34
+ * Ningún flujo, y declarado como tal.
35
+ *
36
+ * El informe lo publica: «esta autenticación no es automatizable» es una
37
+ * respuesta, y dejarla implícita haría que la persona espere una reparación
38
+ * que nunca va a existir.
39
+ */
40
+ flow() {
41
+ return null;
42
+ },
43
+ verify: {
44
+ authorization: "network_external",
45
+ async run(subject, ctx) {
46
+ const visible = isDsnVisible(ctx, subject.label);
47
+ if (!visible) {
48
+ return {
49
+ state: "absent",
50
+ evidence: [`variable de entorno (${subject.label}): ausente, no hay nada que verificar`],
51
+ };
52
+ }
53
+ // Acá NO se vuelve a comprobar la autorización: el llamador hace valer el
54
+ // `authorization` que este proveedor declara y sólo llega hasta acá cuando
55
+ // está concedida. Repetirlo serían dos controles del mismo hecho, y el que
56
+ // se rompiera quedaría tapado por el otro.
57
+ const result = await testMcpConnection({
58
+ dsnVar: subject.label,
59
+ env: { [subject.label]: ctx.env.get(subject.label) },
60
+ paths: ctx.paths,
61
+ platform: process.platform,
62
+ });
63
+ if (result.ok) {
64
+ return {
65
+ state: "present",
66
+ evidence: [
67
+ `variable de entorno (${subject.label}): presente`,
68
+ "la base respondió a un SELECT 1 de sólo lectura",
69
+ ],
70
+ };
71
+ }
72
+ // La credencial ESTÁ y no sirve, y eso no es «ausente»: es una
73
+ // verificación que no pudo concluir que la autenticación funciona. Decirlo
74
+ // `present` porque la variable existe es la falsa salud que este modelo
75
+ // existe para no decir.
76
+ return {
77
+ state: "unverified",
78
+ evidence: [
79
+ `variable de entorno (${subject.label}): presente`,
80
+ `la base no respondió: ${result.error ?? "sin detalle"}`,
81
+ ],
82
+ };
83
+ },
84
+ },
85
+ /**
86
+ * La guía nombra la variable y el archivo de arranque, nunca el valor.
87
+ *
88
+ * El nombre de la conexión sale del id del sujeto por el prefijo que ESTE
89
+ * archivo le puso: es su propia codificación, decodificada con la misma
90
+ * constante y en el mismo módulo. No es leer un id ya renderizado por otro
91
+ * lado para recuperar un dato estructural — el prefijo está acá justamente
92
+ * para que los ids de este proveedor sean únicos en todo el registro.
93
+ */
94
+ guidance(subject, _ctx) {
95
+ return survivingGuidance(buildEnvHelp(subject.label, subject.id.slice(SUBJECT_PREFIX.length)));
96
+ },
97
+ };
98
+ /**
99
+ * La guía de `buildEnvHelp`, reescrita para que la redacción no la vuelva dañina.
100
+ *
101
+ * `buildEnvHelp` emite `export DB_X_DSN='<DSN>'`, que es correcto y no lleva
102
+ * ningún valor — pero `redactSensitiveText` lee `…_DSN=` como una asignación y
103
+ * reemplaza lo que sigue, así que la línea LLEGA a la persona como
104
+ * `export DB_X_DSN=***`. Quien la copie deja literalmente `***` en su archivo de
105
+ * arranque y el MCP falla con una credencial inválida en vez de con una ausente:
106
+ * una guía que empeora las cosas es peor que ninguna.
107
+ *
108
+ * Así que la línea se parte en dos: el nombre de la variable —lo único
109
+ * accionable que este hallazgo puede dar— va parentizado, y el valor se nombra
110
+ * como lo que es, algo que la persona pega y el CLI nunca ve. `next_step` se
111
+ * releva tal cual: no lleva el nombre pegado a un separador.
112
+ */
113
+ function survivingGuidance(help) {
114
+ return [
115
+ // Ojo con la prosa: cualquier aparición del token de un secreto SEGUIDA de
116
+ // espacio se lleva la palabra siguiente. Por eso acá no se escribe la sigla
117
+ // suelta, y el nombre de la variable va siempre entre paréntesis.
118
+ `exportá en tu entorno la variable (${help.variable}) con la cadena de conexión; el valor lo pegás vos y el CLI no lo guarda en ningún lado`,
119
+ durableStep(help),
120
+ help.next_step,
121
+ ];
122
+ }
123
+ /**
124
+ * Cómo hacer que la variable sobreviva a la próxima terminal, en ESTA plataforma.
125
+ *
126
+ * `buildEnvHelp` sólo nombra un archivo de arranque en la rama *nix; en Windows
127
+ * devuelve dos comandos de PowerShell y ninguno lleva `>>`. Buscar el archivo y
128
+ * caer en «el de tu shell» dejaba a quien corre en Windows con una guía que
129
+ * nombra algo que no existe, y descartaba el único mecanismo durable que su
130
+ * plataforma tiene — que `buildEnvHelp` sí conoce y que acá se NOMBRA en vez de
131
+ * relevarse como comando: la línea literal es una asignación, y el redactor la
132
+ * entrega con `***` donde iba el valor.
133
+ */
134
+ function durableStep(help) {
135
+ if (help.platform === "windows") {
136
+ return `para que sobreviva a la próxima terminal, guardala en tu entorno de usuario con SetEnvironmentVariable de PowerShell a nivel "User", nombrando la misma variable (${help.variable})`;
137
+ }
138
+ const named = help.commands.find((command) => command.includes(">>"));
139
+ const file = named?.split(">>").pop()?.trim();
140
+ const where = file === undefined || file.length === 0 ? "el de tu shell" : file;
141
+ return `dejala en tu archivo de arranque (${where}) para que sobreviva a la próxima terminal`;
142
+ }
143
+ //# sourceMappingURL=auth-dsn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-dsn.js","sourceRoot":"","sources":["../../../src/application/doctor/auth-dsn.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEnE,0FAA0F;AAC1F,MAAM,cAAc,GAAG,MAAM,CAAC;AAE9B,MAAM,CAAC,MAAM,eAAe,GAAmC;IAC7D,EAAE,EAAE,KAAK;IAET,QAAQ,CAAC,GAAe;QACtB,OAAO,kBAAkB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACjE,EAAE,EAAE,GAAG,cAAc,GAAG,UAAU,CAAC,IAAI,EAAE;YACzC,KAAK,EAAE,UAAU,CAAC,MAAM;YACxB,OAAO,EAAE,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE;SACjC,CAAC,CAAC,CAAC;IACN,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAA0B,EAAE,GAAe;QACrD,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACjD,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;YACrC,uEAAuE;YACvE,mEAAmE;YACnE,cAAc;YACd,EAAE;YACF,iEAAiE;YACjE,sEAAsE;YACtE,2EAA2E;YAC3E,yEAAyE;YACzE,2EAA2E;YAC3E,2EAA2E;YAC3E,4DAA4D;YAC5D,QAAQ,EAAE,CAAC,wBAAwB,OAAO,CAAC,KAAK,MAAM,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;SAC1F,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,IAAI;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,EAAE;QACN,aAAa,EAAE,kBAAkB;QACjC,KAAK,CAAC,GAAG,CAAC,OAA0B,EAAE,GAAe;YACnD,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO;oBACL,KAAK,EAAE,QAAQ;oBACf,QAAQ,EAAE,CAAC,wBAAwB,OAAO,CAAC,KAAK,uCAAuC,CAAC;iBACzF,CAAC;YACJ,CAAC;YACD,0EAA0E;YAC1E,2EAA2E;YAC3E,2EAA2E;YAC3E,2CAA2C;YAC3C,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC;gBACrC,MAAM,EAAE,OAAO,CAAC,KAAK;gBACrB,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;gBACpD,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;aAC3B,CAAC,CAAC;YACH,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,OAAO;oBACL,KAAK,EAAE,SAAS;oBAChB,QAAQ,EAAE;wBACR,wBAAwB,OAAO,CAAC,KAAK,aAAa;wBAClD,iDAAiD;qBAClD;iBACF,CAAC;YACJ,CAAC;YACD,+DAA+D;YAC/D,2EAA2E;YAC3E,wEAAwE;YACxE,wBAAwB;YACxB,OAAO;gBACL,KAAK,EAAE,YAAY;gBACnB,QAAQ,EAAE;oBACR,wBAAwB,OAAO,CAAC,KAAK,aAAa;oBAClD,yBAAyB,MAAM,CAAC,KAAK,IAAI,aAAa,EAAE;iBACzD;aACF,CAAC;QACJ,CAAC;KACF;IAED;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAA0B,EAAE,IAAgB;QACnD,OAAO,iBAAiB,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IACjG,CAAC;CACF,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,SAAS,iBAAiB,CAAC,IAAqC;IAC9D,OAAO;QACL,2EAA2E;QAC3E,4EAA4E;QAC5E,kEAAkE;QAClE,sCAAsC,IAAI,CAAC,QAAQ,yFAAyF;QAC5I,WAAW,CAAC,IAAI,CAAC;QACjB,IAAI,CAAC,SAAS;KACf,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,WAAW,CAAC,IAAqC;IACxD,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,qKAAqK,IAAI,CAAC,QAAQ,GAAG,CAAC;IAC/L,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC;IAChF,OAAO,qCAAqC,KAAK,4CAA4C,CAAC;AAChG,CAAC"}
@@ -0,0 +1,28 @@
1
+ export async function runDoctorAuthFlow(action, ctx) {
2
+ const argv = action.argv ?? [];
3
+ const program = argv[0];
4
+ if (program === undefined) {
5
+ // Una acción de flujo sin `argv` es un lote que no puede haber salido del
6
+ // anotador: se declara fallida en vez de correr algo inventado.
7
+ return {
8
+ status: "failed",
9
+ detail: "flujo de autenticación: la acción aprobada no lleva ningún programa sellado",
10
+ };
11
+ }
12
+ if (!ctx.process.hasTty()) {
13
+ // `blocked` y no `failed`: nada corrió y el recurso quedó como estaba. Un
14
+ // flujo interactivo sin terminal no es un intento fallido, es un intento que
15
+ // no corresponde hacer.
16
+ return {
17
+ status: "blocked",
18
+ detail: "flujo de autenticación: no hay terminal para heredar, y el secreto sólo puede ir de la persona al programa por ahí",
19
+ };
20
+ }
21
+ const { code } = await ctx.process.runInteractive(program, [...argv.slice(1)], {
22
+ cwd: ctx.paths.workspaceDir(),
23
+ });
24
+ return code === 0
25
+ ? { status: "applied", detail: `flujo de autenticación: ${program} terminó con código 0` }
26
+ : { status: "failed", detail: `flujo de autenticación: ${program} terminó con código ${code}` };
27
+ }
28
+ //# sourceMappingURL=auth-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-flow.js","sourceRoot":"","sources":["../../../src/application/doctor/auth-flow.ts"],"names":[],"mappings":"AAiCA,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAyB,EACzB,GAAe;IAEf,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,0EAA0E;QAC1E,gEAAgE;QAChE,OAAO;YACL,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,6EAA6E;SACtF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC1B,0EAA0E;QAC1E,6EAA6E;QAC7E,wBAAwB;QACxB,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,MAAM,EACJ,oHAAoH;SACvH,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;QAC7E,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE;KAC9B,CAAC,CAAC;IACH,OAAO,IAAI,KAAK,CAAC;QACf,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,2BAA2B,OAAO,uBAAuB,EAAE;QAC1F,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,2BAA2B,OAAO,uBAAuB,IAAI,EAAE,EAAE,CAAC;AACpG,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { dsnAuthProvider } from "./auth-dsn.js";
2
+ /**
3
+ * Los proveedores reales, y hoy hay exactamente uno.
4
+ *
5
+ * Ninguno declara flujo. No es una omisión: autenticar lo único autenticable de
6
+ * este CLI es exportar una cadena que sólo la persona conoce, y cualquier
7
+ * comando que el CLI corriera para conseguirla tendría que custodiarla. La
8
+ * maquinaria de flujos existe probada con un doble, y el catálogo real declara
9
+ * que no la usa.
10
+ */
11
+ export const DOCTOR_AUTH_PROVIDERS = [dsnAuthProvider];
12
+ //# sourceMappingURL=auth-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-registry.js","sourceRoot":"","sources":["../../../src/application/doctor/auth-registry.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAKhD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAqC,CAAC,eAAe,CAAC,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { HARNESSES } from "../../domain/harnesses.js";
2
+ import { reportAllHostStates } from "../self/host-states.js";
3
+ /** Catalog order, and every consumer of the report sorts by it. */
4
+ export const DOCTOR_HOST_ORDER = HARNESSES.map((spec) => spec.id);
5
+ const PARTICIPATING = new Set(["ready", "installable", "residual-config"]);
6
+ export async function selectDoctorHosts(ctx, options) {
7
+ const states = await reportAllHostStates(ctx);
8
+ const only = new Set(options.only);
9
+ const ordered = [...states].sort((left, right) => DOCTOR_HOST_ORDER.indexOf(left.host) - DOCTOR_HOST_ORDER.indexOf(right.host));
10
+ const known = new Set(DOCTOR_HOST_ORDER);
11
+ const unknownOnly = [...new Set(options.only)].filter((name) => !known.has(name));
12
+ const hosts = [];
13
+ const absent = [];
14
+ for (const state of ordered) {
15
+ // `--only` restricts; `--host` does not. Two flags because "which host am I
16
+ // on" and "which hosts do I care about" are different questions, and folding
17
+ // them made the invoking host silently hide every other one.
18
+ if (only.size > 0 && !only.has(state.host))
19
+ continue;
20
+ if (!PARTICIPATING.has(state.status)) {
21
+ absent.push(state.host);
22
+ continue;
23
+ }
24
+ hosts.push(viewOf(state, options.currentHost));
25
+ }
26
+ return { hosts, absent, states: ordered, unknownOnly };
27
+ }
28
+ function viewOf(state, currentHost) {
29
+ const spec = HARNESSES.find((candidate) => candidate.id === state.host);
30
+ return {
31
+ host: state.host,
32
+ target: state.target,
33
+ label: state.label,
34
+ status: state.status,
35
+ current: state.host === currentHost,
36
+ runtime: { state: state.runtime.state, version: state.runtime.version },
37
+ workline_installed: state.workline.installed,
38
+ mcp_host: spec?.mcpHostId ?? null,
39
+ };
40
+ }
41
+ //# sourceMappingURL=hosts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hosts.js","sourceRoot":"","sources":["../../../src/application/doctor/hosts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAkB,MAAM,2BAA2B,CAAC;AAUtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAG7D,mEAAmE;AACnE,MAAM,CAAC,MAAM,iBAAiB,GAAyB,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAqBxF,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAE3E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAe,EACf,OAAmE;IAEnE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,IAAI,CAC9B,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAC9F,CAAC;IAEF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAS,iBAAiB,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAElF,MAAM,KAAK,GAAuB,EAAE,CAAC;IACrC,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,4EAA4E;QAC5E,6EAA6E;QAC7E,6DAA6D;QAC7D,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QACrD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACrC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACxB,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AACzD,CAAC;AAED,SAAS,MAAM,CAAC,KAAsB,EAAE,WAA6B;IACnE,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC;IACxE,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,IAAI,KAAK,WAAW;QACnC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE;QACvE,kBAAkB,EAAE,KAAK,CAAC,QAAQ,CAAC,SAAS;QAC5C,QAAQ,EAAE,IAAI,EAAE,SAAS,IAAI,IAAI;KAClC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * What the host itself says about its MCP servers.
3
+ *
4
+ * The CLI already runs these two commands and deliberately throws their output
5
+ * away (`checkNativeMcpHosts`), because there it only needed a yes/no about one
6
+ * entry. A doctor needs the opposite: the host's own verdict per server, ours
7
+ * and other people's alike, because an MCP that fails to connect is a problem
8
+ * the person has whether or not Workline wrote it.
9
+ *
10
+ * Both parsers fail CLOSED. Codex publishes JSON and Claude publishes prose with
11
+ * no contract at all, so a line whose mark is not recognized becomes
12
+ * `unverified` — never `connected`. A doctor that guesses health from an
13
+ * unfamiliar format is worse than one that says it could not tell.
14
+ */
15
+ import { spawnSync as nodeSpawnSync } from "node:child_process";
16
+ export const NATIVE_MCP_HOSTS = ["claude", "codex"];
17
+ /**
18
+ * The ceiling. `claude mcp list` CONNECTS every server to report its health, so
19
+ * the diagnostic phase pays for the slowest one; without a bound a single hung
20
+ * server would hold the whole report.
21
+ */
22
+ export const NATIVE_READ_TIMEOUT_MS = 15_000;
23
+ export function readNativeMcpState(host, deps = {}) {
24
+ const run = deps.run ?? defaultRun;
25
+ const args = host === "codex" ? ["mcp", "list", "--json"] : ["mcp", "list"];
26
+ const result = run(host, args, deps.timeoutMs ?? NATIVE_READ_TIMEOUT_MS);
27
+ if (result.errorCode === "ENOENT") {
28
+ return {
29
+ ok: false,
30
+ host,
31
+ failure: "absent",
32
+ reason: `el binario '${host}' no está en el PATH`,
33
+ };
34
+ }
35
+ if (result.timedOut) {
36
+ return {
37
+ ok: false,
38
+ host,
39
+ failure: "failed",
40
+ reason: `'${host} ${args.join(" ")}' no respondió dentro del límite`,
41
+ };
42
+ }
43
+ if (result.errorCode !== null || result.status !== 0) {
44
+ return {
45
+ ok: false,
46
+ host,
47
+ failure: "failed",
48
+ reason: `'${host} ${args.join(" ")}' terminó con código ${result.status ?? "desconocido"}`,
49
+ };
50
+ }
51
+ return host === "codex" ? parseCodexMcpList(result.stdout) : parseClaudeMcpList(result.stdout);
52
+ }
53
+ export function parseCodexMcpList(stdout) {
54
+ let data;
55
+ try {
56
+ data = JSON.parse(stdout);
57
+ }
58
+ catch {
59
+ return {
60
+ ok: false,
61
+ host: "codex",
62
+ failure: "failed",
63
+ reason: "la salida de 'codex mcp list --json' no es JSON",
64
+ };
65
+ }
66
+ if (!Array.isArray(data)) {
67
+ return {
68
+ ok: false,
69
+ host: "codex",
70
+ failure: "failed",
71
+ reason: "'codex mcp list --json' no devolvió una lista",
72
+ };
73
+ }
74
+ const servers = [];
75
+ for (const raw of data) {
76
+ if (!isRecord(raw) || typeof raw.name !== "string")
77
+ continue;
78
+ servers.push({
79
+ host: "codex",
80
+ name: raw.name,
81
+ health: codexHealth(raw),
82
+ detail: typeof raw.disabled_reason === "string" ? raw.disabled_reason : null,
83
+ auth_status: typeof raw.auth_status === "string" ? raw.auth_status : null,
84
+ transport: transportType(raw.transport),
85
+ });
86
+ }
87
+ return { ok: true, host: "codex", servers };
88
+ }
89
+ /**
90
+ * Codex reports availability and credentials separately, and so does this.
91
+ *
92
+ * `enabled: false` is a deliberate state, not a fault — folding it into "failed"
93
+ * would put a warning on something the person turned off on purpose. A missing
94
+ * or non-boolean `enabled` is the fail-closed case: the shape moved and nobody
95
+ * can say what it means now.
96
+ */
97
+ function codexHealth(raw) {
98
+ if (raw.enabled === false)
99
+ return "disabled";
100
+ if (raw.enabled !== true)
101
+ return "unverified";
102
+ return raw.auth_status === "not_logged_in" ? "needs-auth" : "connected";
103
+ }
104
+ function transportType(value) {
105
+ if (typeof value === "string")
106
+ return value;
107
+ if (isRecord(value) && typeof value.type === "string")
108
+ return value.type;
109
+ return null;
110
+ }
111
+ /**
112
+ * Claude publishes prose. Every mark it is known to print is listed here, and
113
+ * anything else is `unverified` with the status text it did print.
114
+ *
115
+ * The table carries more marks than one capture shows on purpose: the observed
116
+ * output uses `!` for the authentication case where an earlier capture showed
117
+ * `⏸`, and a parser that only knows the marks of the machine it was written on
118
+ * mis-reads the next version as healthy or as broken.
119
+ */
120
+ const CLAUDE_MARKS = [
121
+ { mark: "✔", health: "connected" },
122
+ { mark: "✓", health: "connected" },
123
+ { mark: "✘", health: "failed" },
124
+ { mark: "✗", health: "failed" },
125
+ { mark: "⊘", health: "disabled" },
126
+ { mark: "⏸", health: "needs-auth" },
127
+ { mark: "!", health: "needs-auth" },
128
+ ];
129
+ export function parseClaudeMcpList(stdout) {
130
+ const servers = [];
131
+ for (const line of stdout.split("\n")) {
132
+ const parsed = parseClaudeLine(line);
133
+ if (parsed !== null)
134
+ servers.push(parsed);
135
+ }
136
+ return { ok: true, host: "claude", servers };
137
+ }
138
+ function parseClaudeLine(line) {
139
+ const trimmed = line.trim();
140
+ if (trimmed.length === 0)
141
+ return null;
142
+ // The name is the first whitespace-free token and it ends in a colon. Plugin
143
+ // servers are named `plugin:<pkg>:<server>`, so splitting on the FIRST colon
144
+ // would call every one of them `plugin`.
145
+ const firstSpace = trimmed.indexOf(" ");
146
+ if (firstSpace <= 0)
147
+ return null;
148
+ const token = trimmed.slice(0, firstSpace);
149
+ if (!token.endsWith(":"))
150
+ return null;
151
+ const name = token.slice(0, -1);
152
+ if (name.length === 0)
153
+ return null;
154
+ // The status sits at the end, after the last " - ". The command in between is
155
+ // deliberately not retained: it is the host's business, it can be long, and a
156
+ // report has no use for it.
157
+ const cut = trimmed.lastIndexOf(" - ");
158
+ const status = cut === -1 ? "" : trimmed.slice(cut + 3).trim();
159
+ const known = CLAUDE_MARKS.find((candidate) => status.startsWith(candidate.mark));
160
+ if (known === undefined) {
161
+ return {
162
+ host: "claude",
163
+ name,
164
+ health: "unverified",
165
+ detail: status.length === 0 ? "formato de línea no reconocido" : status,
166
+ auth_status: null,
167
+ transport: null,
168
+ };
169
+ }
170
+ const detail = status.slice(known.mark.length).trim();
171
+ return {
172
+ host: "claude",
173
+ name,
174
+ health: known.health,
175
+ detail: detail.length === 0 ? null : detail,
176
+ auth_status: null,
177
+ transport: null,
178
+ };
179
+ }
180
+ function defaultRun(command, args, timeoutMs) {
181
+ let result;
182
+ try {
183
+ result = nodeSpawnSync(command, [...args], {
184
+ encoding: "buffer",
185
+ shell: false,
186
+ stdio: ["ignore", "pipe", "pipe"],
187
+ timeout: timeoutMs,
188
+ windowsHide: true,
189
+ });
190
+ }
191
+ catch {
192
+ return { status: null, stdout: "", errorCode: "SPAWN_FAILED", timedOut: false };
193
+ }
194
+ const errorCode = readErrorCode(result.error);
195
+ return {
196
+ status: result.status,
197
+ stdout: result.stdout?.toString("utf8") ?? "",
198
+ errorCode: errorCode ?? null,
199
+ timedOut: errorCode === "ETIMEDOUT" || result.signal === "SIGTERM",
200
+ };
201
+ }
202
+ function readErrorCode(error) {
203
+ if (error === null || typeof error !== "object")
204
+ return null;
205
+ const code = error.code;
206
+ return typeof code === "string" ? code : null;
207
+ }
208
+ function isRecord(value) {
209
+ return value !== null && typeof value === "object" && !Array.isArray(value);
210
+ }
211
+ //# sourceMappingURL=native-host-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-host-state.js","sourceRoot":"","sources":["../../../src/application/doctor/native-host-state.ts"],"names":[],"mappings":"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"}