@vidiemme/copilot-proxy 0.1.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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -0
  3. package/dist/attribution.d.ts +34 -0
  4. package/dist/attribution.js +118 -0
  5. package/dist/attribution.js.map +1 -0
  6. package/dist/autostart.d.ts +10 -0
  7. package/dist/autostart.js +119 -0
  8. package/dist/autostart.js.map +1 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +393 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/collector/forwarder.d.ts +44 -0
  13. package/dist/collector/forwarder.js +203 -0
  14. package/dist/collector/forwarder.js.map +1 -0
  15. package/dist/config.d.ts +44 -0
  16. package/dist/config.js +105 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/defaults.d.ts +33 -0
  19. package/dist/defaults.js +35 -0
  20. package/dist/defaults.js.map +1 -0
  21. package/dist/gitRepository.d.ts +21 -0
  22. package/dist/gitRepository.js +147 -0
  23. package/dist/gitRepository.js.map +1 -0
  24. package/dist/paths.d.ts +12 -0
  25. package/dist/paths.js +39 -0
  26. package/dist/paths.js.map +1 -0
  27. package/dist/projectDetector.d.ts +48 -0
  28. package/dist/projectDetector.js +130 -0
  29. package/dist/projectDetector.js.map +1 -0
  30. package/dist/proxy/handler.d.ts +5 -0
  31. package/dist/proxy/handler.js +149 -0
  32. package/dist/proxy/handler.js.map +1 -0
  33. package/dist/proxy/headers.d.ts +6 -0
  34. package/dist/proxy/headers.js +52 -0
  35. package/dist/proxy/headers.js.map +1 -0
  36. package/dist/proxy/inspectRequest.d.ts +18 -0
  37. package/dist/proxy/inspectRequest.js +41 -0
  38. package/dist/proxy/inspectRequest.js.map +1 -0
  39. package/dist/server.d.ts +7 -0
  40. package/dist/server.js +66 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/usage/collector.d.ts +25 -0
  43. package/dist/usage/collector.js +63 -0
  44. package/dist/usage/collector.js.map +1 -0
  45. package/dist/usage/parseAnthropic.d.ts +23 -0
  46. package/dist/usage/parseAnthropic.js +83 -0
  47. package/dist/usage/parseAnthropic.js.map +1 -0
  48. package/dist/usage/parseOpenAI.d.ts +24 -0
  49. package/dist/usage/parseOpenAI.js +72 -0
  50. package/dist/usage/parseOpenAI.js.map +1 -0
  51. package/dist/usage/sse.d.ts +17 -0
  52. package/dist/usage/sse.js +59 -0
  53. package/dist/usage/sse.js.map +1 -0
  54. package/dist/usage/types.d.ts +23 -0
  55. package/dist/usage/types.js +19 -0
  56. package/dist/usage/types.js.map +1 -0
  57. package/package.json +50 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forwarder.js","sourceRoot":"","sources":["../../src/collector/forwarder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EAAE,oBAAoB,EAA0B,MAAM,kCAAkC,CAAC;AAShG,wFAAwF;AACxF,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,0EAA0E;AAC1E,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAEhC,SAAS,KAAK,CAAI,KAAU,EAAE,IAAY;IACxC,MAAM,MAAM,GAAU,EAAE,CAAC;IACzB,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI,EAAE,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,cAAc;IAUN;IACA;IAVX,KAAK,GAAwB,EAAE,CAAC;IAChC,KAAK,CAA6B;IAClC,OAAO,CAA4B;IACnC,OAAO,GAAG,CAAC,CAAC;IACH,SAAS,CAAS;IAClB,SAAS,CAAS;IAClB,WAAW,CAAS;IAErC,YACmB,MAAoB,EACpB,MAAc;QADd,WAAM,GAAN,MAAM,CAAc;QACpB,WAAM,GAAN,MAAM,CAAQ;QAE/B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC;QACtE,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG,GAAG,MAAM,CAAC,SAAS,UAAU,CAAC;IACnD,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,KAAK;YAAE,OAAO;QACvB,oEAAoE;QACpE,4EAA4E;QAC5E,gEAAgE;QAChE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,kBAAkB,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;YAC5B,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,OAAO,CAAC,KAAwB;QAC9B,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;YAC1C,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;YAClB,IAAI,IAAI,CAAC,OAAO,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,mCAAmC,CAAC,CAAC;YACpF,CAAC;YACD,OAAO;QACT,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvB,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,SAAS;YAAE,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;IAC7D,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACnC,MAAM,GAAG,CAAC;IACZ,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YAExB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;gBACnD,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC9B,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBACtD,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,uBAAuB,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,KAAK;YAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;QACnB,uEAAuE;QACvE,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,MAA2B;QAC5C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAErC,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;gBAC/C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE;iBACtD;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;gBAChC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC;aAC5D,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,2BAA2B,CAAC,CAAC;YACrF,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,QAAQ,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAE7B,iEAAiE;QACjE,wEAAwE;QACxE,mDAAmD;QACnD,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC;QAC7F,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,EAC7D,SAAS,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,2BAA2B,CAC9E,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvD,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAE9C,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;YACvD,IAAI,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAE,CAAC;gBAAE,SAAS;YAC/C,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9C,MAAM;QACR,CAAC;QAED,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAEO,KAAK,CAAC,kBAAkB;QAC9B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,uCAAuC,CAAC,CAAC;QACrF,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACzB,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,IAAY;QACnC,IAAI,OAAe,CAAC;QACpB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,MAAM,GAAwB,EAAE,CAAC;QACvC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;gBAAE,SAAS;YACvC,IAAI,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAsB,CAAC,CAAC;YACrD,CAAC;YAAC,MAAM,CAAC;gBACP,6DAA6D;YAC/D,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,MAA2B;QAC7C,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,KAAK,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAE7E,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAC1C,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EACnB,GAAG,EAAE,CAAC,CAAC,CACR,CAAC;YACF,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC1D,CAAC;iBAAM,CAAC;gBACN,MAAM,UAAU,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;YAC1C,CAAC;YACD,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,+BAA+B,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,SAAS;QACrB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,IAAI,MAAM,CAAC,MAAM,IAAI,gBAAgB;YAAE,OAAO;QAE9C,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,EACxC,wDAAwD,CACzD,CAAC;QACF,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAC5F,IAAI,EAAE,KAAK;SACZ,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,44 @@
1
+ /** Sorgente dei valori di configurazione: `process.env` o una mappa equivalente. */
2
+ export type ConfigSource = Record<string, string | undefined>;
3
+ export interface AttributionMapping {
4
+ projectId?: string;
5
+ developerId?: string;
6
+ }
7
+ export interface ClientConfig {
8
+ port: number;
9
+ host: string;
10
+ logLevel: string;
11
+ upstreamBaseUrl: string;
12
+ upstreamAuthToken: string | undefined;
13
+ tlsKeyPath: string | undefined;
14
+ tlsCertPath: string | undefined;
15
+ /** Endpoint di raccolta, es. `https://copilot-collector.swarm.vidiemme.it/v1/usage`. */
16
+ collectorUrl: string;
17
+ collectorToken: string;
18
+ collectorTimeoutMs: number;
19
+ /** File su cui parcheggiare gli eventi quando il servizio non risponde. */
20
+ spoolPath: string;
21
+ projectHeader: string;
22
+ unassignedProject: string;
23
+ workspaceRoots: string[];
24
+ projectMarkers: string[];
25
+ projectStickyTtlMs: number;
26
+ attributionTokens: Record<string, AttributionMapping>;
27
+ developerIdSalt: string;
28
+ flushIntervalMs: number;
29
+ flushMaxBatch: number;
30
+ }
31
+ /**
32
+ * Costruisce la configurazione da una sorgente di chiavi.
33
+ *
34
+ * La sorgente e' iniettabile perche' il comando `start` sovrappone piu' livelli
35
+ * — file di configurazione utente, ambiente, opzioni della riga di comando —
36
+ * prima di arrivare qui.
37
+ */
38
+ export declare function loadConfig(source?: ConfigSource): ClientConfig;
39
+ /**
40
+ * Pseudonimo stabile e non invertibile derivato da un segreto del client.
41
+ * Serve a distinguere i developer senza conservare credenziali.
42
+ */
43
+ export declare function pseudonymize(secret: string, salt: string): string;
44
+ export declare function stableIdentity(token: string): string;
package/dist/config.js ADDED
@@ -0,0 +1,105 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { DEFAULT_COLLECTOR_URL, DEFAULT_DEVELOPER_ID_SALT, defaultWorkspaceRoots } from './defaults.js';
3
+ import { defaultSpoolPath } from './paths.js';
4
+ function parseAttributionTokens(raw) {
5
+ try {
6
+ const parsed = JSON.parse(raw);
7
+ if (typeof parsed !== 'object' || parsed === null)
8
+ return {};
9
+ return parsed;
10
+ }
11
+ catch {
12
+ throw new Error("ATTRIBUTION_TOKENS non e' un JSON valido");
13
+ }
14
+ }
15
+ /**
16
+ * Costruisce la configurazione da una sorgente di chiavi.
17
+ *
18
+ * La sorgente e' iniettabile perche' il comando `start` sovrappone piu' livelli
19
+ * — file di configurazione utente, ambiente, opzioni della riga di comando —
20
+ * prima di arrivare qui.
21
+ */
22
+ export function loadConfig(source = process.env) {
23
+ const read = (name) => source[name]?.trim() || undefined;
24
+ const required = (name) => {
25
+ const value = read(name);
26
+ if (!value)
27
+ throw new Error(`Configurazione mancante: ${name}`);
28
+ return value;
29
+ };
30
+ const optional = (name, fallback) => read(name) ?? fallback;
31
+ const intOption = (name, fallback) => {
32
+ const parsed = Number.parseInt(optional(name, String(fallback)), 10);
33
+ return Number.isFinite(parsed) ? parsed : fallback;
34
+ };
35
+ const listOption = (name, fallback) => optional(name, fallback)
36
+ .split(',')
37
+ .map((item) => item.trim())
38
+ .filter((item) => item.length > 0);
39
+ const developerIdSalt = optional('DEVELOPER_ID_SALT', DEFAULT_DEVELOPER_ID_SALT);
40
+ if (developerIdSalt.length === 0 || developerIdSalt === 'change-me') {
41
+ throw new Error('DEVELOPER_ID_SALT deve essere impostato con un valore casuale: protegge lo pseudonimo del developer dal reverse lookup. Deve essere lo stesso su tutte le postazioni, altrimenti la stessa persona risulta come piu\' developer diversi');
42
+ }
43
+ const collectorUrl = optional('COLLECTOR_URL', DEFAULT_COLLECTOR_URL);
44
+ if (collectorUrl.startsWith('http://') &&
45
+ !/^https?:\/\/(localhost|127\.0\.0\.1)/.test(collectorUrl)) {
46
+ throw new Error('COLLECTOR_URL deve usare https: in chiaro il token di ingest sarebbe leggibile sulla rete');
47
+ }
48
+ return {
49
+ port: intOption('PORT', 8787),
50
+ host: optional('HOST', '127.0.0.1'),
51
+ logLevel: optional('LOG_LEVEL', 'info'),
52
+ upstreamBaseUrl: optional('UPSTREAM_BASE_URL', 'https://api.githubcopilot.com').replace(/\/+$/, ''),
53
+ upstreamAuthToken: read('UPSTREAM_AUTH_TOKEN'),
54
+ tlsKeyPath: read('TLS_KEY_PATH'),
55
+ tlsCertPath: read('TLS_CERT_PATH'),
56
+ collectorUrl,
57
+ collectorToken: required('COLLECTOR_TOKEN'),
58
+ collectorTimeoutMs: intOption('COLLECTOR_TIMEOUT_MS', 10_000),
59
+ spoolPath: optional('SPOOL_PATH', defaultSpoolPath()),
60
+ projectHeader: optional('PROJECT_HEADER', 'x-project-id').toLowerCase(),
61
+ unassignedProject: optional('UNASSIGNED_PROJECT', 'unassigned'),
62
+ workspaceRoots: listOption('WORKSPACE_ROOTS', defaultWorkspaceRoots()),
63
+ projectMarkers: listOption('PROJECT_MARKERS', '.git,.hg,.svn'),
64
+ projectStickyTtlMs: intOption('PROJECT_STICKY_TTL_MS', 30 * 60_000),
65
+ attributionTokens: parseAttributionTokens(optional('ATTRIBUTION_TOKENS', '{}')),
66
+ developerIdSalt,
67
+ flushIntervalMs: intOption('FLUSH_INTERVAL_MS', 5000),
68
+ flushMaxBatch: intOption('FLUSH_MAX_BATCH', 100),
69
+ };
70
+ }
71
+ /**
72
+ * Pseudonimo stabile e non invertibile derivato da un segreto del client.
73
+ * Serve a distinguere i developer senza conservare credenziali.
74
+ */
75
+ export function pseudonymize(secret, salt) {
76
+ return createHash('sha256').update(`${salt}:${secret}`).digest('hex').slice(0, 16);
77
+ }
78
+ /**
79
+ * Estrae dalla credenziale la porzione che identifica la persona.
80
+ *
81
+ * Il token Copilot e' una lista di coppie `chiave=valore` separate da `;` e
82
+ * viene rinnovato di continuo: campi come `exp` cambiano a ogni rotazione. Fare
83
+ * l'hash del token intero produrrebbe un developer diverso ogni mezz'ora,
84
+ * frammentando qualsiasi analisi nel tempo. Si isolano quindi i soli campi
85
+ * stabili, con fallback al token completo per credenziali di altro formato.
86
+ */
87
+ const STABLE_TOKEN_FIELDS = ['u', 'tid', 'oid', 'sid'];
88
+ export function stableIdentity(token) {
89
+ if (!token.includes('=') || !token.includes(';'))
90
+ return token;
91
+ const fields = new Map();
92
+ for (const pair of token.split(';')) {
93
+ const separator = pair.indexOf('=');
94
+ if (separator <= 0)
95
+ continue;
96
+ fields.set(pair.slice(0, separator).trim().toLowerCase(), pair.slice(separator + 1).trim());
97
+ }
98
+ for (const key of STABLE_TOKEN_FIELDS) {
99
+ const value = fields.get(key);
100
+ if (value)
101
+ return `${key}:${value}`;
102
+ }
103
+ return token;
104
+ }
105
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Valori aziendali committati nel pacchetto.
3
+ *
4
+ * Il proxy viene installato con `npx` da chi non conosce — ne' deve conoscere —
5
+ * l'infrastruttura di raccolta: se questi valori fossero da passare a mano, ogni
6
+ * postazione sarebbe un'occasione per sbagliarli. Stanno qui, non in un `.env`,
7
+ * perche' un file di ambiente sulla macchina del developer e' esattamente cio'
8
+ * che si vuole evitare. Restano sovrascrivibili da opzione o variabile
9
+ * d'ambiente per lo sviluppo del proxy stesso.
10
+ */
11
+ /** Endpoint di ingest del servizio di raccolta. */
12
+ export declare const DEFAULT_COLLECTOR_URL = "https://copilot-collector.swarm.vidiemme.it/v1/usage";
13
+ /**
14
+ * Salt degli pseudonimi developer.
15
+ *
16
+ * Deve essere identico su tutte le postazioni: e' cio' che rende la stessa
17
+ * persona confrontabile fra macchine e nel tempo. Cambiarlo spezza la
18
+ * continuita' dello storico, perche' da quel momento la stessa persona compare
19
+ * con un id diverso.
20
+ *
21
+ * Sta nel sorgente e non fra i segreti: non protegge un accesso, rende solo non
22
+ * banale risalire dall'id alla credenziale da cui e' derivato. Chi ha il
23
+ * database conosce comunque le persone che ci lavorano.
24
+ */
25
+ export declare const DEFAULT_DEVELOPER_ID_SALT = "44e342883d198dd2744dd9b485dce715f871e7c2c41dc8aa9ecb64b02b20a015";
26
+ /**
27
+ * Cartelle sotto cui cercare i repository.
28
+ *
29
+ * La home e' il default che funziona ovunque senza chiedere nulla: delimita i
30
+ * path che il proxy puo' risolvere, e nessuno tiene i propri repository fuori
31
+ * dalla propria home. Chi vuole restringere il campo passa `--workspace-roots`.
32
+ */
33
+ export declare const defaultWorkspaceRoots: () => string;
@@ -0,0 +1,35 @@
1
+ import { homedir } from 'node:os';
2
+ /**
3
+ * Valori aziendali committati nel pacchetto.
4
+ *
5
+ * Il proxy viene installato con `npx` da chi non conosce — ne' deve conoscere —
6
+ * l'infrastruttura di raccolta: se questi valori fossero da passare a mano, ogni
7
+ * postazione sarebbe un'occasione per sbagliarli. Stanno qui, non in un `.env`,
8
+ * perche' un file di ambiente sulla macchina del developer e' esattamente cio'
9
+ * che si vuole evitare. Restano sovrascrivibili da opzione o variabile
10
+ * d'ambiente per lo sviluppo del proxy stesso.
11
+ */
12
+ /** Endpoint di ingest del servizio di raccolta. */
13
+ export const DEFAULT_COLLECTOR_URL = 'https://copilot-collector.swarm.vidiemme.it/v1/usage';
14
+ /**
15
+ * Salt degli pseudonimi developer.
16
+ *
17
+ * Deve essere identico su tutte le postazioni: e' cio' che rende la stessa
18
+ * persona confrontabile fra macchine e nel tempo. Cambiarlo spezza la
19
+ * continuita' dello storico, perche' da quel momento la stessa persona compare
20
+ * con un id diverso.
21
+ *
22
+ * Sta nel sorgente e non fra i segreti: non protegge un accesso, rende solo non
23
+ * banale risalire dall'id alla credenziale da cui e' derivato. Chi ha il
24
+ * database conosce comunque le persone che ci lavorano.
25
+ */
26
+ export const DEFAULT_DEVELOPER_ID_SALT = '44e342883d198dd2744dd9b485dce715f871e7c2c41dc8aa9ecb64b02b20a015';
27
+ /**
28
+ * Cartelle sotto cui cercare i repository.
29
+ *
30
+ * La home e' il default che funziona ovunque senza chiedere nulla: delimita i
31
+ * path che il proxy puo' risolvere, e nessuno tiene i propri repository fuori
32
+ * dalla propria home. Chi vuole restringere il campo passa `--workspace-roots`.
33
+ */
34
+ export const defaultWorkspaceRoots = () => homedir();
35
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC;;;;;;;;;GASG;AAEH,mDAAmD;AACnD,MAAM,CAAC,MAAM,qBAAqB,GAAG,sDAAsD,CAAC;AAE5F;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,yBAAyB,GACpC,kEAAkE,CAAC;AAErE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAW,EAAE,CAAC,OAAO,EAAE,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { RepositoryIdentity } from '@vidiemme/copilot-usage-contract';
2
+ export type { RepositoryIdentity };
3
+ /**
4
+ * Scompone un URL di remote nei suoi segmenti, coprendo le forme in uso:
5
+ * `git@host:gruppo/repo.git`, `ssh://git@host:22/gruppo/repo`,
6
+ * `https://host/gruppo/sottogruppo/repo.git`, percorsi locali.
7
+ */
8
+ export declare function parseRemoteUrl(raw: string): {
9
+ host: string | null;
10
+ segments: string[];
11
+ };
12
+ /**
13
+ * Ricava l'identita' del progetto dal remote Git invece che dal nome della
14
+ * cartella.
15
+ *
16
+ * Il nome della cartella lo sceglie chi clona ed e' quindi diverso da macchina
17
+ * a macchina; il percorso sul server Git no. Conservare anche i gruppi parent
18
+ * permette di aggregare in seguito per cliente, business unit o qualunque
19
+ * livello della gerarchia, senza dover riclassificare a mano.
20
+ */
21
+ export declare function readRepositoryIdentity(projectRoot: string): RepositoryIdentity;
@@ -0,0 +1,147 @@
1
+ import { readFileSync, statSync } from 'node:fs';
2
+ import { basename, isAbsolute, join, resolve, sep } from 'node:path';
3
+ import { sanitizeIdentifier } from './attribution.js';
4
+ const REMOTE_HEADER = /^\s*\[\s*remote\s+"([^"]+)"\s*\]/;
5
+ const SECTION_HEADER = /^\s*\[/;
6
+ const URL_ENTRY = /^\s*url\s*=\s*(.+?)\s*$/;
7
+ const GITDIR_ENTRY = /^gitdir:\s*(.+)$/m;
8
+ const MAX_CONFIG_BYTES = 256 * 1024;
9
+ const MAX_PROJECT_ID_LENGTH = 160;
10
+ /**
11
+ * Individua la directory di metadati Git del progetto.
12
+ *
13
+ * In un worktree o in un submodule `.git` non e' una cartella ma un file che
14
+ * punta altrove; per i worktree il puntatore finisce dentro `worktrees/<nome>`,
15
+ * mentre la configurazione dei remote vive nella directory principale.
16
+ */
17
+ function resolveGitDir(projectRoot) {
18
+ const gitPath = join(projectRoot, '.git');
19
+ let stats;
20
+ try {
21
+ stats = statSync(gitPath);
22
+ }
23
+ catch {
24
+ return undefined;
25
+ }
26
+ if (stats.isDirectory())
27
+ return gitPath;
28
+ let pointer;
29
+ try {
30
+ pointer = readFileSync(gitPath, 'utf-8');
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ const match = GITDIR_ENTRY.exec(pointer);
36
+ if (!match)
37
+ return undefined;
38
+ const target = match[1].trim();
39
+ const absolute = isAbsolute(target) ? target : resolve(projectRoot, target);
40
+ const worktrees = absolute.indexOf(`${sep}worktrees${sep}`);
41
+ return worktrees >= 0 ? absolute.slice(0, worktrees) : absolute;
42
+ }
43
+ /** Legge gli URL dei remote da un file di configurazione Git. */
44
+ function readRemotes(gitDir) {
45
+ const remotes = new Map();
46
+ let content;
47
+ try {
48
+ const configPath = join(gitDir, 'config');
49
+ if (statSync(configPath).size > MAX_CONFIG_BYTES)
50
+ return remotes;
51
+ content = readFileSync(configPath, 'utf-8');
52
+ }
53
+ catch {
54
+ return remotes;
55
+ }
56
+ let current;
57
+ for (const line of content.split('\n')) {
58
+ const header = REMOTE_HEADER.exec(line);
59
+ if (header) {
60
+ current = header[1];
61
+ continue;
62
+ }
63
+ if (SECTION_HEADER.test(line)) {
64
+ current = undefined;
65
+ continue;
66
+ }
67
+ if (!current)
68
+ continue;
69
+ const entry = URL_ENTRY.exec(line);
70
+ if (entry && !remotes.has(current))
71
+ remotes.set(current, entry[1]);
72
+ }
73
+ return remotes;
74
+ }
75
+ /**
76
+ * Scompone un URL di remote nei suoi segmenti, coprendo le forme in uso:
77
+ * `git@host:gruppo/repo.git`, `ssh://git@host:22/gruppo/repo`,
78
+ * `https://host/gruppo/sottogruppo/repo.git`, percorsi locali.
79
+ */
80
+ export function parseRemoteUrl(raw) {
81
+ const url = raw.trim().replace(/\/+$/, '').replace(/\.git$/i, '');
82
+ if (url.length === 0)
83
+ return { host: null, segments: [] };
84
+ if (url.startsWith('/') || url.startsWith('.') || url.startsWith('file:')) {
85
+ return { host: null, segments: [basename(url)] };
86
+ }
87
+ const scheme = /^[a-z][a-z0-9+.-]*:\/\/(.*)$/i.exec(url);
88
+ let host = null;
89
+ let path;
90
+ if (scheme) {
91
+ const rest = scheme[1];
92
+ const slash = rest.indexOf('/');
93
+ if (slash < 0)
94
+ return { host: null, segments: [] };
95
+ host = rest.slice(0, slash).replace(/^.*@/, '').replace(/:\d+$/, '') || null;
96
+ path = rest.slice(slash + 1);
97
+ }
98
+ else {
99
+ // Forma scp: [utente@]host:percorso
100
+ const scp = /^(?:[^@]+@)?([^:/]+):(.+)$/.exec(url);
101
+ if (!scp)
102
+ return { host: null, segments: [basename(url)] };
103
+ host = scp[1];
104
+ path = scp[2];
105
+ }
106
+ return { host, segments: path.split('/').filter((segment) => segment.length > 0) };
107
+ }
108
+ /**
109
+ * Ricava l'identita' del progetto dal remote Git invece che dal nome della
110
+ * cartella.
111
+ *
112
+ * Il nome della cartella lo sceglie chi clona ed e' quindi diverso da macchina
113
+ * a macchina; il percorso sul server Git no. Conservare anche i gruppi parent
114
+ * permette di aggregare in seguito per cliente, business unit o qualunque
115
+ * livello della gerarchia, senza dover riclassificare a mano.
116
+ */
117
+ export function readRepositoryIdentity(projectRoot) {
118
+ const fallbackName = sanitizeIdentifier(basename(projectRoot)) ?? 'unknown';
119
+ const fallback = {
120
+ projectId: fallbackName,
121
+ host: null,
122
+ groups: [],
123
+ name: fallbackName,
124
+ remoteUrl: null,
125
+ };
126
+ const gitDir = resolveGitDir(projectRoot);
127
+ if (!gitDir)
128
+ return fallback;
129
+ const remotes = readRemotes(gitDir);
130
+ const remoteUrl = remotes.get('origin') ?? remotes.get('upstream') ?? remotes.values().next().value;
131
+ if (!remoteUrl)
132
+ return fallback;
133
+ const { host, segments } = parseRemoteUrl(remoteUrl);
134
+ const clean = segments
135
+ .map((segment) => sanitizeIdentifier(segment))
136
+ .filter((segment) => segment !== undefined);
137
+ if (clean.length === 0)
138
+ return fallback;
139
+ return {
140
+ projectId: clean.join('/').slice(0, MAX_PROJECT_ID_LENGTH),
141
+ host,
142
+ groups: clean.slice(0, -1),
143
+ name: clean[clean.length - 1],
144
+ remoteUrl,
145
+ };
146
+ }
147
+ //# sourceMappingURL=gitRepository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitRepository.js","sourceRoot":"","sources":["../src/gitRepository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Cartella dove il client tiene configurazione e stato.
3
+ *
4
+ * Sotto `npx` la working directory e' quella da cui il developer ha lanciato il
5
+ * comando, cioe' un posto qualsiasi: file di configurazione e spool devono
6
+ * stare in una posizione stabile, non relativa alla cwd.
7
+ */
8
+ export declare function configDir(): string;
9
+ export declare function configFile(): string;
10
+ export declare function defaultSpoolPath(): string;
11
+ /** Percorso del `settings.json` utente di VS Code, per la piattaforma corrente. */
12
+ export declare function vscodeSettingsFile(): string;
package/dist/paths.js ADDED
@@ -0,0 +1,39 @@
1
+ import { homedir } from 'node:os';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * Cartella dove il client tiene configurazione e stato.
5
+ *
6
+ * Sotto `npx` la working directory e' quella da cui il developer ha lanciato il
7
+ * comando, cioe' un posto qualsiasi: file di configurazione e spool devono
8
+ * stare in una posizione stabile, non relativa alla cwd.
9
+ */
10
+ export function configDir() {
11
+ const override = process.env.COPILOT_PROXY_HOME?.trim();
12
+ if (override)
13
+ return override;
14
+ if (process.platform === 'win32') {
15
+ const appData = process.env.APPDATA?.trim();
16
+ if (appData)
17
+ return join(appData, 'copilot-proxy');
18
+ }
19
+ const xdg = process.env.XDG_CONFIG_HOME?.trim();
20
+ return join(xdg || join(homedir(), '.config'), 'copilot-proxy');
21
+ }
22
+ export function configFile() {
23
+ return join(configDir(), 'config.json');
24
+ }
25
+ export function defaultSpoolPath() {
26
+ return join(configDir(), 'spool.jsonl');
27
+ }
28
+ /** Percorso del `settings.json` utente di VS Code, per la piattaforma corrente. */
29
+ export function vscodeSettingsFile() {
30
+ if (process.platform === 'win32') {
31
+ const appData = process.env.APPDATA?.trim() ?? join(homedir(), 'AppData', 'Roaming');
32
+ return join(appData, 'Code', 'User', 'settings.json');
33
+ }
34
+ if (process.platform === 'darwin') {
35
+ return join(homedir(), 'Library', 'Application Support', 'Code', 'User', 'settings.json');
36
+ }
37
+ return join(homedir(), '.config', 'Code', 'User', 'settings.json');
38
+ }
39
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,UAAU,SAAS;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IACxD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;QAC5C,IAAI,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACrD,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IAChD,OAAO,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,EAAE,eAAe,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAC;AAC1C,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,kBAAkB;IAChC,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;IAC5F,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { type RepositoryIdentity } from './gitRepository.js';
2
+ export interface ProjectDetectorOptions {
3
+ /** Cartelle sotto cui vivono i progetti: delimitano cosa e' lecito risolvere. */
4
+ roots: string[];
5
+ /** File o cartelle che marcano la radice di un progetto (tipicamente `.git`). */
6
+ markers: string[];
7
+ /** Durata dell'ereditarieta' del progetto sulle richieste senza path. */
8
+ stickyTtlMs: number;
9
+ /** Limite di corpo ispezionato, per non pagare scansioni su payload enormi. */
10
+ maxScanBytes: number;
11
+ }
12
+ export interface DetectedProject {
13
+ repository: RepositoryIdentity;
14
+ /** `workspace` = dedotto dai path nella richiesta; `session` = ereditato. */
15
+ source: 'workspace' | 'session';
16
+ }
17
+ /**
18
+ * Deduce il progetto di appartenenza di una richiesta dai path assoluti che
19
+ * questa cita.
20
+ *
21
+ * Le richieste di Copilot Chat trasportano il contesto di lavoro: file aperti,
22
+ * riferimenti espliciti, risultati degli strumenti dell'agente. Tutti nominano
23
+ * file reali sul disco. Risalendo da quei path fino al marker di progetto piu'
24
+ * vicino si ottiene l'attribuzione senza chiedere al developer di configurare
25
+ * nulla per ogni repository, e senza conservare il contenuto della richiesta:
26
+ * dei path si tiene solo l'identita' del repository.
27
+ */
28
+ export declare class ProjectDetector {
29
+ private readonly roots;
30
+ private readonly markers;
31
+ private readonly stickyTtlMs;
32
+ private readonly maxScanBytes;
33
+ private readonly pattern;
34
+ /** Path candidato -> repository risolto (o `null` se fuori da ogni progetto). */
35
+ private readonly cache;
36
+ private readonly sticky;
37
+ constructor(options: ProjectDetectorOptions);
38
+ get enabled(): boolean;
39
+ /**
40
+ * @param sessionKey chiave della finestra/conversazione, usata per ereditare
41
+ * il progetto nelle richieste che non citano file (titoli, domande secche).
42
+ */
43
+ detect(body: Buffer, sessionKey: string, now?: number): DetectedProject | undefined;
44
+ private fromBody;
45
+ /** Risale dal path fino al primo marker di progetto, senza uscire dal root. */
46
+ private projectFor;
47
+ private remember;
48
+ }