@ornexus/neocortex 4.60.16 → 4.63.3
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.
- package/dist/sbom.cdx.json +29 -29
- package/docs/install/installer-diagnostics.md +33 -0
- package/install.ps1 +49 -229
- package/install.sh +30 -92
- package/package.json +5 -2
- package/packages/client/dist/adapters/platform-detector.d.ts +7 -6
- package/packages/client/dist/adapters/platform-detector.js +1 -1
- package/packages/client/dist/agent/refresh-stubs.js +1 -1
- package/packages/client/dist/cache/encrypted-cache.d.ts +10 -4
- package/packages/client/dist/cache/encrypted-cache.js +1 -1
- package/packages/client/dist/cache/in-memory-asset-cache.d.ts +5 -4
- package/packages/client/dist/cache/in-memory-asset-cache.js +1 -1
- package/packages/client/dist/cache/protected-pi-boundary.d.ts +6 -2
- package/packages/client/dist/cache/protected-pi-boundary.js +1 -1
- package/packages/client/dist/checkpoint/checkpoint-client-reader.d.ts +31 -30
- package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -2
- package/packages/client/dist/checkpoint/shared-checkpoint-types.d.ts +2 -0
- package/packages/client/dist/cli.js +3 -3
- package/packages/client/dist/commands/invoke.d.ts +77 -1
- package/packages/client/dist/commands/invoke.js +44 -59
- package/packages/client/dist/config/resolver-selection.d.ts +12 -31
- package/packages/client/dist/config/resolver-selection.js +1 -1
- package/packages/client/dist/errors/error-messages.js +1 -1
- package/packages/client/dist/evidence/collector.d.ts +18 -0
- package/packages/client/dist/evidence/collector.js +1 -0
- package/packages/client/dist/evidence/index.d.ts +3 -0
- package/packages/client/dist/evidence/index.js +1 -0
- package/packages/client/dist/evidence/types.d.ts +59 -0
- package/packages/client/dist/evidence/types.js +0 -0
- package/packages/client/dist/graph-retrieval/pre-command-hook.d.ts +21 -0
- package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -1
- package/packages/client/dist/index.d.ts +10 -11
- package/packages/client/dist/index.js +1 -1
- package/packages/client/dist/license/license-client.d.ts +17 -0
- package/packages/client/dist/license/license-client.js +1 -1
- package/packages/client/dist/memory/project-memory-writer.js +13 -13
- package/packages/client/dist/memory/shared-project-memory-types.d.ts +1 -1
- package/packages/client/dist/memory/shared-project-memory-types.js +2 -2
- package/packages/client/dist/resolvers/asset-resolver.d.ts +8 -71
- package/packages/client/dist/resolvers/remote-resolver.d.ts +7 -69
- package/packages/client/dist/resolvers/remote-resolver.js +1 -1
- package/packages/client/dist/runner-cli.js +0 -0
- package/packages/client/dist/state/project-state-snapshot.js +1 -1
- package/packages/client/dist/telemetry/index.d.ts +1 -1
- package/packages/client/dist/telemetry/index.js +1 -1
- package/packages/client/dist/telemetry/offline-queue.d.ts +12 -2
- package/packages/client/dist/telemetry/offline-queue.js +1 -1
- package/packages/client/dist/types/index.d.ts +26 -8
- package/packages/client/dist/types/index.js +1 -1
- package/packages/client/dist/types/shared-public-execution-contract.d.ts +175 -0
- package/packages/client/dist/types/shared-public-execution-contract.js +2 -0
- package/targets-stubs/antigravity/gemini.md +1 -1
- package/targets-stubs/antigravity/skill/SKILL.md +1 -1
- package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex-root.md +2 -2
- package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
- package/targets-stubs/claude-code/neocortex.md +2 -2
- package/targets-stubs/codex/AGENTS.md +16 -6
- package/targets-stubs/codex/README.md +24 -0
- package/targets-stubs/codex/install-codex.sh +70 -1
- package/targets-stubs/codex/neocortex-local.config.toml +17 -0
- package/targets-stubs/codex/neocortex.toml +10 -1
- package/targets-stubs/cursor/agent.md +2 -2
- package/targets-stubs/gemini-cli/agent.md +2 -2
- package/targets-stubs/opencode/neocortex-root.md +4 -4
- package/targets-stubs/opencode/neocortex.md +1 -1
- package/targets-stubs/vscode/neocortex.agent.md +2 -2
- package/packages/client/dist/resolvers/local-resolver.d.ts +0 -26
- package/packages/client/dist/resolvers/local-resolver.js +0 -8
|
@@ -2,39 +2,20 @@
|
|
|
2
2
|
* @license FSL-1.1
|
|
3
3
|
* Copyright (c) 2026 OrNexus AI
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Change Date: February 20, 2029
|
|
9
|
-
* Change License: MIT
|
|
10
|
-
*
|
|
11
|
-
* See the LICENSE file in the project root for full license text.
|
|
5
|
+
* Production resolver selection is deliberately remote-only. Local protected
|
|
6
|
+
* asset resolution remains source-development code and is never imported,
|
|
7
|
+
* discovered or selected by the published client.
|
|
12
8
|
*/
|
|
13
|
-
import type {
|
|
9
|
+
import type { PublicCapabilityResolver } from '../resolvers/asset-resolver.js';
|
|
14
10
|
import type { CreateResolverOptions } from '../types/index.js';
|
|
15
|
-
/** Result of resolver selection including the reason for the choice */
|
|
16
11
|
export interface ResolverSelectionResult {
|
|
17
|
-
readonly resolver:
|
|
18
|
-
readonly reason:
|
|
19
|
-
readonly mode: '
|
|
12
|
+
readonly resolver: PublicCapabilityResolver;
|
|
13
|
+
readonly reason: 'public-capability-remote-only';
|
|
14
|
+
readonly mode: 'remote';
|
|
20
15
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* 2. NEOCORTEX_MODE=local -> LocalResolver
|
|
27
|
-
* 3. NEOCORTEX_MODE=remote -> RemoteResolver
|
|
28
|
-
* 4. core/ exists locally -> LocalResolver
|
|
29
|
-
* 5. License key + no core/ -> RemoteResolver
|
|
30
|
-
* 6. Default -> LocalResolver
|
|
31
|
-
*
|
|
32
|
-
* @param options - Optional configuration overrides
|
|
33
|
-
* @returns Configured AssetResolver ready for use
|
|
34
|
-
*/
|
|
35
|
-
export declare function createResolver(options?: CreateResolverOptions): Promise<AssetResolver>;
|
|
36
|
-
/**
|
|
37
|
-
* Select resolver with full result including reason.
|
|
38
|
-
* Useful for logging/debugging why a specific resolver was chosen.
|
|
39
|
-
*/
|
|
16
|
+
export declare class DevelopmentResolverUnavailableError extends Error {
|
|
17
|
+
readonly code = "LOCAL_RESOLVER_DEVELOPMENT_ONLY";
|
|
18
|
+
constructor();
|
|
19
|
+
}
|
|
20
|
+
export declare function createResolver(options?: CreateResolverOptions): Promise<PublicCapabilityResolver>;
|
|
40
21
|
export declare function selectResolver(options?: CreateResolverOptions): Promise<ResolverSelectionResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{RemoteResolver as r}from"../resolvers/remote-resolver.js";import{DEFAULT_SERVER_URL as o}from"../constants.js";class l extends Error{code="LOCAL_RESOLVER_DEVELOPMENT_ONLY";constructor(){super("LOCAL_RESOLVER_DEVELOPMENT_ONLY: published clients execute public directives and cannot resolve protected local assets."),this.name="DevelopmentResolverUnavailableError"}}function s(e){return e?.forceLocal===!0||process.env.NEOCORTEX_MODE?.toLowerCase()==="local"}async function E(e){return(await c(e)).resolver}async function c(e){if(s(e))throw new l;return{resolver:new r({serverUrl:e?.serverUrl||process.env.NEOCORTEX_SERVER_URL||o,licenseKey:e?.licenseKey||process.env.NEOCORTEX_LICENSE_KEY||"",cacheProvider:e?.cacheProvider,licenseClient:e?.licenseClient}),reason:"public-capability-remote-only",mode:"remote"}}export{l as DevelopmentResolverUnavailableError,E as createResolver,c as selectResolver};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const t="support@neocortex.sh",u={AUTH_EXPIRED:{en:{summary:"Your session has expired.",whatHappened:"The token we use to authenticate your CLI has expired. This is normal and happens every few hours.",whatToDo:"Re-activate with the license key that was emailed to you.",command:"neocortex activate YOUR-LICENSE-KEY",url:"https://neocortex.sh/portal"},"pt-BR":{summary:"Sua sess\xE3o expirou.",whatHappened:"O token de autentica\xE7\xE3o do CLI expirou. Isso \xE9 normal e acontece a cada poucas horas.",whatToDo:"Reative o CLI com a license key que voc\xEA recebeu por email.",command:"neocortex activate SUA-LICENSE-KEY",url:"https://neocortex.sh/portal"}},UPGRADE_REQUIRED:{en:{summary:"Your CLI version is outdated.",whatHappened:"The server requires a newer CLI version. Older versions are not allowed for security and compatibility reasons.",whatToDo:"Install the latest CLI globally with npm.",command:"npm install -g @ornexus/neocortex@latest"},"pt-BR":{summary:"Sua vers\xE3o do CLI est\xE1 desatualizada.",whatHappened:"O servidor exige uma vers\xE3o mais recente do CLI. Vers\xF5es antigas n\xE3o s\xE3o permitidas por motivos de seguran\xE7a e compatibilidade.",whatToDo:"Instale a vers\xE3o mais recente globalmente via npm.",command:"npm install -g @ornexus/neocortex@latest"}},RATE_LIMITED:{en:{summary:"You sent too many requests in a short window.",whatHappened:"You hit the rate limit for your plan. This protects the service from abuse and keeps it fast for everyone.",whatToDo:"Wait a few seconds and try again. If you hit this often, upgrading your plan raises the limit.",url:"https://neocortex.sh/portal/plans"},"pt-BR":{summary:"Voc\xEA fez muitas requisi\xE7\xF5es em pouco tempo.",whatHappened:"O limite de taxa do seu plano foi atingido. Isso protege o servi\xE7o contra abuso e mant\xE9m a velocidade para todos.",whatToDo:"Espere alguns segundos e tente novamente. Se isso acontece com frequ\xEAncia, fazer upgrade do seu plano aumenta o limite.",url:"https://neocortex.sh/portal/plans"}},TRIGGER_NOT_ALLOWED:{en:{summary:"This command is not available on your current plan.",whatHappened:"You tried to use a trigger that requires a paid plan (Pro or Enterprise).",whatToDo:"See the full comparison and upgrade in the portal.",url:"https://neocortex.sh/portal/plans"},"pt-BR":{summary:"Este comando n\xE3o est\xE1 dispon\xEDvel no seu plano atual.",whatHappened:"Voc\xEA tentou usar um trigger que requer um plano pago (Pro ou Enterprise).",whatToDo:"Veja a compara\xE7\xE3o completa e fa\xE7a upgrade no portal.",url:"https://neocortex.sh/portal/plans"}},QUOTA_EXCEEDED:{en:{summary:"Daily quota reached.",whatHappened:"You have used all invocations allowed by your plan today. Quotas reset at midnight UTC.",whatToDo:"Wait for the daily reset, or upgrade your plan for a higher quota.",url:"https://neocortex.sh/portal/plans"},"pt-BR":{summary:"Quota di\xE1ria atingida.",whatHappened:"Voc\xEA usou todas as invoca\xE7\xF5es permitidas pelo seu plano hoje. As quotas s\xE3o resetadas \xE0 meia-noite UTC.",whatToDo:"Aguarde o reset di\xE1rio ou fa\xE7a upgrade do plano para uma quota maior.",url:"https://neocortex.sh/portal/plans"}},SERVER_ERROR:{en:{summary:"Server error.",whatHappened:"Something went wrong on our side. We have logged the error and will investigate.",whatToDo:`Try again in a minute. If the problem persists, please contact ${t} with the details.`},"pt-BR":{summary:"Erro do servidor.",whatHappened:"Algo deu errado no nosso lado. O erro foi registrado e vamos investigar.",whatToDo:`Tente novamente em um minuto. Se o problema persistir, entre em contato: ${t}.`}},ECONNREFUSED:{en:{summary:"Cannot reach the Neocortex server.",whatHappened:"We could not open a connection to the server. This is usually a network problem on your side.",whatToDo:"Check your internet connection, any VPN or corporate proxy, and try again."},"pt-BR":{summary:"N\xE3o foi poss\xEDvel alcan\xE7ar o servidor Neocortex.",whatHappened:"N\xE3o conseguimos abrir uma conex\xE3o com o servidor. Isso geralmente \xE9 um problema de rede do seu lado.",whatToDo:"Verifique sua conex\xE3o, qualquer VPN ou proxy corporativo, e tente novamente."}},MACHINE_LIMIT_EXCEEDED:{en:{summary:"Machine limit reached.",whatHappened:"Your plan allows a limited number of active machines, and this one would exceed it.",whatToDo:"Deactivate a machine you no longer use from the portal, then re-run activate here.",url:"https://neocortex.sh/portal/machines"},"pt-BR":{summary:"Limite de m\xE1quinas atingido.",whatHappened:"Seu plano permite um n\xFAmero limitado de m\xE1quinas ativas, e esta ultrapassaria o limite.",whatToDo:"Desative uma m\xE1quina que voc\xEA n\xE3o usa mais no portal e rode activate aqui de novo.",url:"https://neocortex.sh/portal/machines"}},NOT_CONFIGURED:{en:{summary:"Neocortex is not configured on this machine.",whatHappened:"No license key was found. You need to run `neocortex activate` once before using the CLI.",whatToDo:"Get a license key from the portal and activate.",command:"neocortex activate YOUR-LICENSE-KEY",url:"https://neocortex.sh/portal"},"pt-BR":{summary:"Neocortex n\xE3o est\xE1 configurado nesta m\xE1quina.",whatHappened:"Nenhuma license key encontrada. Voc\xEA precisa rodar `neocortex activate` uma vez antes de usar o CLI.",whatToDo:"Pegue uma license key no portal e ative.",command:"neocortex activate SUA-LICENSE-KEY",url:"https://neocortex.sh/portal"}}};function r(o=process.env){return(o.LC_ALL??o.LANG??"").toLowerCase().startsWith("pt")?"pt-BR":"en"}function p(o,a=r()){const e=u[o];return e?e[a]??e.en??null:null}function c(o,a=r()){const e=[];e.push(""),e.push(`[Neocortex] ${o.summary}`),e.push("");const n=a==="pt-BR"?"O que aconteceu":"What happened",s=a==="pt-BR"?"O que fazer":"What to do",i=a==="pt-BR"?`Precisa de ajuda? ${t}`:`Need help? ${t}`;return e.push(`${n}: ${o.whatHappened}`),e.push(`${s}: ${o.whatToDo}`),o.command&&(e.push(""),e.push(` ${o.command}`)),o.url&&(e.push(""),e.push(` ${o.url}`)),e.push(""),e.push(i),e.push(""),e.join(`
|
|
1
|
+
const t="support@neocortex.sh",u={AUTH_EXPIRED:{en:{summary:"Your session has expired.",whatHappened:"The token we use to authenticate your CLI has expired. This is normal and happens every few hours.",whatToDo:"Re-activate with the license key that was emailed to you.",command:"neocortex activate YOUR-LICENSE-KEY",url:"https://neocortex.sh/portal"},"pt-BR":{summary:"Sua sess\xE3o expirou.",whatHappened:"O token de autentica\xE7\xE3o do CLI expirou. Isso \xE9 normal e acontece a cada poucas horas.",whatToDo:"Reative o CLI com a license key que voc\xEA recebeu por email.",command:"neocortex activate SUA-LICENSE-KEY",url:"https://neocortex.sh/portal"}},UPGRADE_REQUIRED:{en:{summary:"Your CLI version is outdated.",whatHappened:"The server requires a newer CLI version. Older versions are not allowed for security and compatibility reasons.",whatToDo:"Install the latest CLI globally with npm.",command:"npm install -g @ornexus/neocortex@latest"},"pt-BR":{summary:"Sua vers\xE3o do CLI est\xE1 desatualizada.",whatHappened:"O servidor exige uma vers\xE3o mais recente do CLI. Vers\xF5es antigas n\xE3o s\xE3o permitidas por motivos de seguran\xE7a e compatibilidade.",whatToDo:"Instale a vers\xE3o mais recente globalmente via npm.",command:"npm install -g @ornexus/neocortex@latest"}},RATE_LIMITED:{en:{summary:"You sent too many requests in a short window.",whatHappened:"You hit the rate limit for your plan. This protects the service from abuse and keeps it fast for everyone.",whatToDo:"Wait a few seconds and try again. If you hit this often, upgrading your plan raises the limit.",url:"https://neocortex.sh/portal/plans"},"pt-BR":{summary:"Voc\xEA fez muitas requisi\xE7\xF5es em pouco tempo.",whatHappened:"O limite de taxa do seu plano foi atingido. Isso protege o servi\xE7o contra abuso e mant\xE9m a velocidade para todos.",whatToDo:"Espere alguns segundos e tente novamente. Se isso acontece com frequ\xEAncia, fazer upgrade do seu plano aumenta o limite.",url:"https://neocortex.sh/portal/plans"}},TRIGGER_NOT_ALLOWED:{en:{summary:"This command is not available on your current plan.",whatHappened:"You tried to use a trigger that requires a paid plan (Pro or Enterprise).",whatToDo:"See the full comparison and upgrade in the portal.",url:"https://neocortex.sh/portal/plans"},"pt-BR":{summary:"Este comando n\xE3o est\xE1 dispon\xEDvel no seu plano atual.",whatHappened:"Voc\xEA tentou usar um trigger que requer um plano pago (Pro ou Enterprise).",whatToDo:"Veja a compara\xE7\xE3o completa e fa\xE7a upgrade no portal.",url:"https://neocortex.sh/portal/plans"}},QUOTA_EXCEEDED:{en:{summary:"Daily quota reached.",whatHappened:"You have used all invocations allowed by your plan today. Quotas reset at midnight UTC.",whatToDo:"Wait for the daily reset, or upgrade your plan for a higher quota.",url:"https://neocortex.sh/portal/plans"},"pt-BR":{summary:"Quota di\xE1ria atingida.",whatHappened:"Voc\xEA usou todas as invoca\xE7\xF5es permitidas pelo seu plano hoje. As quotas s\xE3o resetadas \xE0 meia-noite UTC.",whatToDo:"Aguarde o reset di\xE1rio ou fa\xE7a upgrade do plano para uma quota maior.",url:"https://neocortex.sh/portal/plans"}},SERVER_ERROR:{en:{summary:"Server error.",whatHappened:"Something went wrong on our side. We have logged the error and will investigate.",whatToDo:`Try again in a minute. If the problem persists, please contact ${t} with the details.`},"pt-BR":{summary:"Erro do servidor.",whatHappened:"Algo deu errado no nosso lado. O erro foi registrado e vamos investigar.",whatToDo:`Tente novamente em um minuto. Se o problema persistir, entre em contato: ${t}.`}},ECONNREFUSED:{en:{summary:"Cannot reach the Neocortex server.",whatHappened:"We could not open a connection to the server. This is usually a network problem on your side.",whatToDo:"Check your internet connection, any VPN or corporate proxy, and try again."},"pt-BR":{summary:"N\xE3o foi poss\xEDvel alcan\xE7ar o servidor Neocortex.",whatHappened:"N\xE3o conseguimos abrir uma conex\xE3o com o servidor. Isso geralmente \xE9 um problema de rede do seu lado.",whatToDo:"Verifique sua conex\xE3o, qualquer VPN ou proxy corporativo, e tente novamente."}},MACHINE_LIMIT_EXCEEDED:{en:{summary:"Machine limit reached.",whatHappened:"Your plan allows a limited number of active machines, and this one would exceed it.",whatToDo:"Deactivate a machine you no longer use from the portal, then re-run activate here.",url:"https://neocortex.sh/portal/machines"},"pt-BR":{summary:"Limite de m\xE1quinas atingido.",whatHappened:"Seu plano permite um n\xFAmero limitado de m\xE1quinas ativas, e esta ultrapassaria o limite.",whatToDo:"Desative uma m\xE1quina que voc\xEA n\xE3o usa mais no portal e rode activate aqui de novo.",url:"https://neocortex.sh/portal/machines"}},NOT_CONFIGURED:{en:{summary:"Neocortex is not configured on this machine.",whatHappened:"No license key was found. You need to run `neocortex activate` once before using the CLI.",whatToDo:"Get a license key from the portal and activate.",command:"neocortex activate YOUR-LICENSE-KEY",url:"https://neocortex.sh/portal"},"pt-BR":{summary:"Neocortex n\xE3o est\xE1 configurado nesta m\xE1quina.",whatHappened:"Nenhuma license key encontrada. Voc\xEA precisa rodar `neocortex activate` uma vez antes de usar o CLI.",whatToDo:"Pegue uma license key no portal e ative.",command:"neocortex activate SUA-LICENSE-KEY",url:"https://neocortex.sh/portal"}},CODEX_AUTH_SANDBOX:{en:{summary:"Codex cannot use your local Neocortex activation.",whatHappened:"The Codex runtime could not access or use the local Neocortex auth data under ~/.neocortex. Your local machine may already be activated, but this Codex profile or sandbox cannot use it.",whatToDo:"Use a trusted local Codex profile/session with Full access to ~/.neocortex and outbound auth network access, or run Neocortex from your local terminal. Do not paste license or API keys into prompts; activate an isolated Codex environment only if you intentionally want a separate activation.",url:"https://neocortex.sh/portal/login"},"pt-BR":{summary:"O Codex n\xE3o consegue usar sua ativa\xE7\xE3o local do Neocortex.",whatHappened:"O runtime do Codex n\xE3o conseguiu acessar ou usar os dados locais de autentica\xE7\xE3o do Neocortex em ~/.neocortex. Sua m\xE1quina local pode j\xE1 estar ativada, mas este perfil ou sandbox do Codex n\xE3o consegue usar essa ativa\xE7\xE3o.",whatToDo:"Use um perfil/sess\xE3o local e confi\xE1vel do Codex com acesso total (Full access) a ~/.neocortex e acesso de rede para autentica\xE7\xE3o, ou rode o Neocortex no seu terminal local. N\xE3o cole license keys ou API keys em prompts; ative um ambiente Codex isolado apenas se voc\xEA quiser uma ativa\xE7\xE3o separada de prop\xF3sito.",url:"https://neocortex.sh/portal/login"}}};function r(o=process.env){return(o.LC_ALL??o.LANG??"").toLowerCase().startsWith("pt")?"pt-BR":"en"}function p(o,a=r()){const e=u[o];return e?e[a]??e.en??null:null}function c(o,a=r()){const e=[];e.push(""),e.push(`[Neocortex] ${o.summary}`),e.push("");const n=a==="pt-BR"?"O que aconteceu":"What happened",s=a==="pt-BR"?"O que fazer":"What to do",i=a==="pt-BR"?`Precisa de ajuda? ${t}`:`Need help? ${t}`;return e.push(`${n}: ${o.whatHappened}`),e.push(`${s}: ${o.whatToDo}`),o.command&&(e.push(""),e.push(` ${o.command}`)),o.url&&(e.push(""),e.push(` ${o.url}`)),e.push(""),e.push(i),e.push(""),e.join(`
|
|
2
2
|
`)}function l(o){if(!o||typeof o!="object")return null;const a=o;return typeof a.code=="string"&&(a.code==="ECONNREFUSED"||a.code==="ENOTFOUND"||a.code==="ETIMEDOUT"||a.code==="ECONNRESET")||typeof a.message=="string"&&(/connect/i.test(a.message)&&/refus/i.test(a.message)||/fetch failed/i.test(a.message))?"ECONNREFUSED":null}export{r as detectErrorLocale,c as formatHumanizedError,p as humanizeError,l as inferErrorCodeFromException};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProjectEvidenceBudget, ProjectEvidenceConsent, ProjectEvidenceEnvelope, ProjectEvidenceRedactionPolicy } from './types.js';
|
|
2
|
+
export declare const CLIENT_PROJECT_EVIDENCE_BUDGET: ProjectEvidenceBudget;
|
|
3
|
+
export interface RichProjectEvidenceCandidate {
|
|
4
|
+
readonly path: string;
|
|
5
|
+
readonly kind: 'screenshot' | 'live_evidence';
|
|
6
|
+
readonly redactionPolicy?: ProjectEvidenceRedactionPolicy;
|
|
7
|
+
readonly expiresAt?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface CollectProjectEvidenceOptions {
|
|
10
|
+
readonly projectRoot: string;
|
|
11
|
+
readonly candidatePaths?: readonly string[];
|
|
12
|
+
readonly richCandidates?: readonly RichProjectEvidenceCandidate[];
|
|
13
|
+
readonly consent?: Partial<ProjectEvidenceConsent>;
|
|
14
|
+
readonly collectedAt?: string;
|
|
15
|
+
readonly nowIso?: string;
|
|
16
|
+
readonly budget?: Partial<ProjectEvidenceBudget>;
|
|
17
|
+
}
|
|
18
|
+
export declare function collectProjectEvidence(options: CollectProjectEvidenceOptions): ProjectEvidenceEnvelope;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as G}from"node:crypto";import{lstatSync as w,readdirSync as J,readFileSync as L,realpathSync as I,statSync as O}from"node:fs";import{isAbsolute as z,relative as D,resolve as $}from"node:path";const V=Object.freeze({maxItems:48,maxFileBytes:96*1024,maxTotalBytes:512*1024,maxSummaryChars:280,maxEnvelopeBytes:64*1024,maxExclusions:64}),j=512,E=12,R=3600*1e3,T=300*1e3,B=/(?:\.tsx?|\.jsx?|\.vue|\.svelte|\.css|\.scss|\.json|\.ya?ml|\.mdx?|\.html)$/i,q=/\.(?:png|jpe?g|webp)$/i,X=new Set([".git",".neocortex","node_modules","dist","build","coverage","core","private","secrets","credentials","raw-logs"]),M=/(?:[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}|\b(?:api[-_ ]?key|license[-_ ]?key|password|secret|token)\b\s*[:=]|\b(?:sk|pk|ghp|github_pat)_[A-Za-z0-9_-]{12,}|https?:\/\/(?:localhost|127\.0\.0\.1|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(?:1[6-9]|2\d|3[01])\.\d+\.\d+|[^/\s]+\.(?:local|internal))\b|private\s+(?:prompt|workflow|customer data)|-----BEGIN [A-Z ]+PRIVATE KEY-----)/i,F=new Set(["metadata-only-v1","visual-pii-v1","strict-v1"]),K=/(?:\bDROP\s+(?:TABLE|COLUMN|DATABASE)\b|\bTRUNCATE\s+TABLE\b|\brm\s+-rf\s+(?:src|app|pages|components)\b)/i;function g(t){return G("sha256").update(t).digest("hex")}function k(t){if(Array.isArray(t))return`[${t.map(k).join(",")}]`;if(t&&typeof t=="object"){const e=t;return`{${Object.keys(e).sort().map(s=>`${JSON.stringify(s)}:${k(e[s])}`).join(",")}}`}return JSON.stringify(t)??"null"}function b(t){return t.trim().replace(/\\/g,"/").replace(/\/+/g,"/").replace(/^\.\//,"")}function H(t){const e=b(t);return!e||z(t)||e.startsWith("/")||/^[a-z]:[\\/]/i.test(t)?"absolute_path_rejected":e===".."||e.startsWith("../")||e.includes("/../")?"traversal_path_rejected":null}function Y(t){return`evidence:${g(t).slice(0,16)}`}function u(t,e){return{sourceId:Y(t),reasonCode:e}}function C(t){return b(t).toLowerCase().split("/").some(s=>s.startsWith(".env")||X.has(s))}function A(t,e){const s=D(t,e);return s===""||!s.startsWith("..")&&!z(s)}function P(t,e,s,n){if(!(s.length>=j))for(const c of J(e,{withFileTypes:!0}).sort((a,i)=>a.name.localeCompare(i.name))){if(s.length>=j)break;const a=$(e,c.name),i=b(D(t,a));if(!C(i)){if(c.isSymbolicLink()){n.push(u(i,"symlink_escape_rejected"));continue}if(c.isDirectory()){P(t,a,s,n);continue}c.isFile()&&B.test(c.name)&&s.push(i)}}}function Q(t){const e=t.toLowerCase();return/\.(?:stories|story)\.(?:tsx?|jsx?|mdx?)$/.test(e)||e.includes("/.storybook/")?"storybook":/(?:^|\/)(?:__tests__|tests?|e2e)(?:\/|$)|\.(?:test|spec)\.(?:tsx?|jsx?)$|playwright|vitest|jest/.test(e)?"validation":/(?:^|\/)(?:routes?|pages?|app)(?:\/|$)|(?:^|\/)router\./.test(e)?"route":/(?:^|\/)(?:components?|ui)(?:\/|$)|[A-Z][A-Za-z0-9_-]*\.(?:tsx|jsx|vue|svelte)$/.test(t)?"component":/(?:tokens?|theme|tailwind|design-system)|\.(?:css|scss)$/.test(e)?"token":/(?:openapi|asyncapi|contracts?|schemas?|events?)|\.(?:graphql|proto)$/.test(e)?"contract":e==="package.json"||e.startsWith("docs/architecture")||e.startsWith("docs/arquitetura-software")?"source_summary":null}function ee(t,e){const s=e.split(/\r?\n/).length,n=new Set,c=[/\bexport\s+(?:default\s+)?(?:async\s+)?(?:function|class|const|let|var|interface|type|enum)\s+([A-Za-z_$][\w$]*)/g,/\b(?:GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\b/g,/--([a-z][a-z0-9-]{1,64})\s*:/gi];for(const a of c)for(const i of e.matchAll(a)){const o=(i[1]??i[0]).replace(/^--/,"");if(/^[A-Za-z_$][\w$-]{0,64}$/.test(o)&&n.add(o),n.size>=12)break}return`${t}; lines=${s}; identifiers=${[...n].sort().join(",")||"none"}`}function te(t){const e=t.consent??{},s=e.redactionPolicy&&F.has(e.redactionPolicy)?e.redactionPolicy:void 0,n=typeof e.expiresAt=="string"?e.expiresAt:void 0;return{richEvidence:e.richEvidence===!0&&!!s,screenshots:e.screenshots===!0&&e.richEvidence===!0&&!!s,liveEvidence:e.liveEvidence===!0&&e.richEvidence===!0&&!!s,...s?{redactionPolicy:s}:{},...n?{expiresAt:n}:{}}}function se(t,e,s,n){const c=H(e);if(c)return{exclusion:u(e,c)};if(C(e)||M.test(e))return{exclusion:u(e,"private_evidence_rejected")};if(!s||!B.test(e))return{exclusion:u(e,"unsupported_file_type")};const a=$(t,e);if(!A(t,a))return{exclusion:u(e,"traversal_path_rejected")};if(w(a).isSymbolicLink())return{exclusion:u(e,"symlink_escape_rejected")};const o=I(a);if(!A(t,o))return{exclusion:u(e,"symlink_escape_rejected")};const d=O(o);if(!d.isFile())return{exclusion:u(e,"unsupported_file_type")};if(d.size>n.maxFileBytes)return{exclusion:u(e,"oversized_evidence")};const x=L(o),r=x.toString("utf8");if(x.includes(0)||M.test(r))return{exclusion:u(e,"private_evidence_rejected")};const y=ee(s,r).slice(0,n.maxSummaryChars),f=b(e),m=g(x);return{item:{id:`${s}:${g(`${f}:${m}`).slice(0,20)}`,kind:s,source:{path:f,contentHash:m,byteLength:d.size},summary:y},unsafeMigration:ce(f,r)}}function ne(t,e,s,n,c,a){const i=H(e.path);if(i)return{exclusion:u(e.path,i)};if(!q.test(e.path))return{exclusion:u(e.path,"unsupported_file_type")};if(!s.richEvidence||(e.kind==="screenshot"?!s.screenshots:!s.liveEvidence))return{exclusion:u(e.path,"consent_required")};if(!e.redactionPolicy||!F.has(e.redactionPolicy)||e.redactionPolicy!==s.redactionPolicy)return{exclusion:u(e.path,"redaction_policy_required")};if(!e.expiresAt||e.expiresAt!==s.expiresAt)return{exclusion:u(e.path,"ttl_invalid")};const o=Date.parse(e.expiresAt);if(!Number.isFinite(o)||o<=c||o-c>R||c>a+T||o<=a-T||o>a+R+T)return{exclusion:u(e.path,"ttl_invalid")};if(C(e.path))return{exclusion:u(e.path,"private_evidence_rejected")};const d=$(t,e.path);if(!A(t,d))return{exclusion:u(e.path,"traversal_path_rejected")};if(w(d).isSymbolicLink())return{exclusion:u(e.path,"symlink_escape_rejected")};const r=I(d);if(!A(t,r))return{exclusion:u(e.path,"symlink_escape_rejected")};const y=O(r);if(!y.isFile())return{exclusion:u(e.path,"unsupported_file_type")};if(y.size>n.maxFileBytes)return{exclusion:u(e.path,"oversized_evidence")};const f=L(r),m={path:b(e.path),contentHash:g(f),byteLength:y.size};return{item:{id:`${e.kind}:${g(`${m.path}:${m.contentHash}`).slice(0,20)}`,kind:e.kind,source:m,summary:`${e.kind}; metadata-only; bytes=${m.byteLength}`,consent:{redactionPolicy:e.redactionPolicy,expiresAt:e.expiresAt}}}}function pe(t){const e=I(t.projectRoot),s=new Date(t.collectedAt??Date.now()).toISOString(),n=Date.parse(s),c=Date.parse(t.nowIso??new Date().toISOString()),a=Number.isFinite(c)?c:Date.now(),i={...V,...t.budget},o=te(t),d=[],x=[];t.candidatePaths?x.push(...t.candidatePaths):P(e,e,x,d);const r=[],y=[];let f=0;for(const h of[...new Set(x)].sort()){const p=b(h);let _;try{_=se(e,h,Q(p),i)}catch{_={exclusion:u(h,"malformed_evidence")}}if(_.exclusion&&d.push(_.exclusion),!!_.item){if(r.length>=i.maxItems||f+_.item.source.byteLength>i.maxTotalBytes){d.push(u(h,"budget_exceeded"));continue}r.push(_.item),_.unsafeMigration&&y.push(_.item.id),f+=_.item.source.byteLength}}for(const h of t.richCandidates??[]){let p;try{p=ne(e,h,o,i,n,a)}catch{p={exclusion:u(h.path,"malformed_evidence")}}if(p.exclusion&&d.push(p.exclusion),!!p.item){if(r.length>=i.maxItems||f+p.item.source.byteLength>i.maxTotalBytes){d.push(u(h.path,"budget_exceeded"));continue}r.push(p.item),f+=p.item.source.byteLength}}r.sort((h,p)=>h.kind.localeCompare(p.kind)||h.source.path.localeCompare(p.source.path)||h.id.localeCompare(p.id));const m=re(r,y),S=d.slice(0,i.maxExclusions),v=g(k({evidence:r,structuralSignals:m}));let l={schemaVersion:1,envelopeId:`evidence-${v.slice(0,24)}`,evidenceHash:v,collectedAt:s,consent:o,budget:{...i,acceptedItems:r.length,acceptedBytes:f},evidence:r,structuralSignals:m,exclusions:S};for(;Buffer.byteLength(JSON.stringify(l),"utf8")>i.maxEnvelopeBytes&&l.evidence.length>0;){const h=l.evidence.at(-1),p=l.evidence.slice(0,-1),_=ie(l.structuralSignals,p),N=g(k({evidence:p,structuralSignals:_??[]}));l={...l,envelopeId:`evidence-${N.slice(0,24)}`,evidenceHash:N,budget:{...l.budget,acceptedItems:p.length,acceptedBytes:p.reduce((Z,W)=>Z+W.source.byteLength,0)},evidence:p,structuralSignals:_,exclusions:[...l.exclusions,u(h.id,"budget_exceeded")].slice(0,i.maxExclusions)}}return l}function re(t,e){const s=t.filter(r=>r.kind!=="screenshot"&&r.kind!=="live_evidence"),n=s.filter(r=>r.kind==="route"||r.kind==="component"),c=n.length>0?n:s.filter(r=>r.kind==="storybook"),a=c.map(r=>r.id),i=(r,y,f,m)=>({category:r,count:Math.min(j,Math.max(0,y)),confidence:f,evidenceIds:[...new Set(m)].sort().slice(0,E)}),o=(r,y)=>{const f=s.filter(l=>l.kind===y),S=(r==="contract_gap"?c.filter(l=>l.kind==="route"):r==="token_gap"?c.filter(l=>l.kind==="component"):c).filter(l=>!oe(l,f,r)),v=S.map(l=>l.id).sort().slice(0,E);return i(r,S.length,"high",v)},d=a.sort().slice(0,E),x=[...new Set(e)].sort().slice(0,E);return[i("ui_surface",c.length,"high",d),o("validation_gap","validation"),o("storybook_gap","storybook"),o("contract_gap","contract"),o("token_gap","token"),i("unsafe_migration",e.length,"high",x)]}function oe(t,e,s){if(s==="token_gap")return e.length>0;if(s==="contract_gap"&&e.some(c=>/(?:^|\/)(?:openapi|asyncapi)(?:\.|\/)/i.test(c.source.path)))return!0;const n=U(t.source.path);return e.some(c=>U(c.source.path)===n)}function U(t){const e=b(t).toLowerCase().split("/");let s=e.at(-1)??"";return s=s.replace(/\.[^.]+$/,"").replace(/\.(?:stories|story|test|spec)$/,""),s==="index"&&e.length>1&&(s=e.at(-2)??s),s.replace(/[^a-z0-9]+/g,"")}function ce(t,e){if(!/(?:^|\/)package\.json$/i.test(t))return!1;try{const s=JSON.parse(e);return!s.scripts||typeof s.scripts!="object"||Array.isArray(s.scripts)?!1:Object.values(s.scripts).some(n=>typeof n=="string"&&K.test(n))}catch{return!1}}function ie(t,e){if(!t)return;const s=new Map(e.map(n=>[n.id,n]));return t.flatMap(n=>{if(n.count===0)return[{...n,evidenceIds:[],count:0}];const c=o=>n.category==="unsafe_migration"?o?.kind==="source_summary"&&/(?:^|\/)package\.json$/i.test(o.source.path):n.category==="contract_gap"?o?.kind==="route":n.category==="token_gap"?o?.kind==="component":o?.kind==="route"||o?.kind==="component"||o?.kind==="storybook",a=e.filter(o=>c(o)).length,i=n.evidenceIds.filter(o=>c(s.get(o))).slice(0,Math.min(n.count,a));return i.length>0&&a>0?[{...n,count:Math.min(n.count,a),evidenceIds:i}]:[]})}export{V as CLIENT_PROJECT_EVIDENCE_BUDGET,pe as collectProjectEvidence};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { CLIENT_PROJECT_EVIDENCE_BUDGET, collectProjectEvidence } from './collector.js';
|
|
2
|
+
export type { CollectProjectEvidenceOptions, RichProjectEvidenceCandidate, } from './collector.js';
|
|
3
|
+
export type { ProjectEvidenceEnvelope, ProjectEvidenceExclusionCode, ProjectEvidenceItem, ProjectEvidenceKind, } from './types.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{CLIENT_PROJECT_EVIDENCE_BUDGET as c,collectProjectEvidence as o}from"./collector.js";export{c as CLIENT_PROJECT_EVIDENCE_BUDGET,o as collectProjectEvidence};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Runtime-local mirror of the public P201.12 contract (no shared package import). */
|
|
2
|
+
export type ProjectEvidenceKind = 'route' | 'component' | 'token' | 'storybook' | 'contract' | 'source_summary' | 'validation' | 'screenshot' | 'live_evidence';
|
|
3
|
+
export type ProjectEvidenceExclusionCode = 'absolute_path_rejected' | 'traversal_path_rejected' | 'symlink_escape_rejected' | 'unsupported_file_type' | 'oversized_evidence' | 'private_evidence_rejected' | 'consent_required' | 'redaction_policy_required' | 'ttl_invalid' | 'budget_exceeded' | 'malformed_evidence';
|
|
4
|
+
export type ProjectEvidenceRedactionPolicy = 'metadata-only-v1' | 'visual-pii-v1' | 'strict-v1';
|
|
5
|
+
export type ProjectEvidenceStructuralSignalCategory = 'ui_surface' | 'validation_gap' | 'storybook_gap' | 'contract_gap' | 'token_gap' | 'unsafe_migration';
|
|
6
|
+
export type ProjectEvidenceStructuralSignalConfidence = 'high' | 'medium' | 'low';
|
|
7
|
+
export interface ProjectEvidenceBudget {
|
|
8
|
+
readonly maxItems: number;
|
|
9
|
+
readonly maxFileBytes: number;
|
|
10
|
+
readonly maxTotalBytes: number;
|
|
11
|
+
readonly maxSummaryChars: number;
|
|
12
|
+
readonly maxEnvelopeBytes: number;
|
|
13
|
+
readonly maxExclusions: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ProjectEvidenceConsent {
|
|
16
|
+
readonly richEvidence: boolean;
|
|
17
|
+
readonly screenshots: boolean;
|
|
18
|
+
readonly liveEvidence: boolean;
|
|
19
|
+
readonly redactionPolicy?: ProjectEvidenceRedactionPolicy;
|
|
20
|
+
readonly expiresAt?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ProjectEvidenceItem {
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly kind: ProjectEvidenceKind;
|
|
25
|
+
readonly source: {
|
|
26
|
+
readonly path: string;
|
|
27
|
+
readonly contentHash: string;
|
|
28
|
+
readonly byteLength: number;
|
|
29
|
+
};
|
|
30
|
+
readonly summary: string;
|
|
31
|
+
readonly consent?: {
|
|
32
|
+
readonly redactionPolicy: ProjectEvidenceRedactionPolicy;
|
|
33
|
+
readonly expiresAt: string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export interface ProjectEvidenceExclusion {
|
|
37
|
+
readonly sourceId: string;
|
|
38
|
+
readonly reasonCode: ProjectEvidenceExclusionCode;
|
|
39
|
+
}
|
|
40
|
+
export interface ProjectEvidenceStructuralSignal {
|
|
41
|
+
readonly category: ProjectEvidenceStructuralSignalCategory;
|
|
42
|
+
readonly count: number;
|
|
43
|
+
readonly confidence: ProjectEvidenceStructuralSignalConfidence;
|
|
44
|
+
readonly evidenceIds: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
export interface ProjectEvidenceEnvelope {
|
|
47
|
+
readonly schemaVersion: 1;
|
|
48
|
+
readonly envelopeId: string;
|
|
49
|
+
readonly evidenceHash: string;
|
|
50
|
+
readonly collectedAt: string;
|
|
51
|
+
readonly consent: ProjectEvidenceConsent;
|
|
52
|
+
readonly budget: ProjectEvidenceBudget & {
|
|
53
|
+
readonly acceptedItems: number;
|
|
54
|
+
readonly acceptedBytes: number;
|
|
55
|
+
};
|
|
56
|
+
readonly evidence: readonly ProjectEvidenceItem[];
|
|
57
|
+
readonly structuralSignals?: readonly ProjectEvidenceStructuralSignal[];
|
|
58
|
+
readonly exclusions: readonly ProjectEvidenceExclusion[];
|
|
59
|
+
}
|
|
File without changes
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* whether to consume this auxiliary metadata.
|
|
8
8
|
*/
|
|
9
9
|
import { type CommandContextRetrievalProfile, type GraphRetrievalMetadata } from './shared-graph-retrieval-contract.js';
|
|
10
|
+
import type { ProjectEvidenceEnvelope } from '../evidence/types.js';
|
|
10
11
|
declare const CONTRACT_VERSION = "client-pre-command-v1";
|
|
11
12
|
export interface GraphRetrievalHookContext {
|
|
12
13
|
readonly args: string;
|
|
@@ -30,5 +31,25 @@ export interface GraphRetrievalHookResult {
|
|
|
30
31
|
readonly metadata?: GraphRetrievalEnrichmentMetadata;
|
|
31
32
|
readonly warning?: string;
|
|
32
33
|
}
|
|
34
|
+
export interface ProjectEvidenceHookContext {
|
|
35
|
+
readonly args: string;
|
|
36
|
+
readonly projectRoot: string;
|
|
37
|
+
readonly enabled?: boolean;
|
|
38
|
+
readonly nowIso?: string;
|
|
39
|
+
readonly logger?: {
|
|
40
|
+
readonly warn?: (msg: string) => void;
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export interface ProjectEvidenceHookResult {
|
|
44
|
+
readonly applied: boolean;
|
|
45
|
+
readonly reason: 'disabled' | 'command_not_supported' | 'applied' | 'hook_error';
|
|
46
|
+
readonly envelope?: ProjectEvidenceEnvelope;
|
|
47
|
+
readonly warning?: string;
|
|
48
|
+
}
|
|
33
49
|
export declare function runGraphRetrievalHook(ctx: GraphRetrievalHookContext): Promise<GraphRetrievalHookResult>;
|
|
50
|
+
/**
|
|
51
|
+
* P201.12 local-only brownfield inventory. This runs independently from the
|
|
52
|
+
* optional graph feature flag because it replaces remote `projectRoot` reads.
|
|
53
|
+
*/
|
|
54
|
+
export declare function runProjectEvidenceHook(ctx: ProjectEvidenceHookContext): Promise<ProjectEvidenceHookResult>;
|
|
34
55
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash as
|
|
1
|
+
import{createHash as T}from"node:crypto";import{existsSync as v,readFileSync as f,statSync as I}from"node:fs";import{join as h}from"node:path";import{DEFAULT_GRAPH_RETRIEVAL_BUDGETS as y,createGraphRetrievalMetadata as g,normalizeGraphRetrievalPath as i,resolveClientCommandContextPolicy as P}from"./shared-graph-retrieval-contract.js";import{collectProjectEvidence as E}from"../evidence/collector.js";const p="client-pre-command-v1",A="1970-01-01T00:00:00.000Z";function b(e){return P(e)}function u(e){return T("sha256").update(e).digest("hex")}function m(e){const t=i(e);return t.length===0||t.startsWith("/")||t.startsWith("..")||t.includes("/../")||/(^|\/)core(?:\/|$)/i.test(t)||/(^|\/)\.env(?:$|[./-])/i.test(t)||/(^|\/)(?:credentials?|secrets?|tokens?|private-prompts?|raw-logs?)(?:\.|\/|$)/i.test(t)||/\.(?:sqlite|db|pem|key|p12|pfx|crt|cer|der|bin)$/i.test(t)}function k(e,t){const n=i(t);if(m(n))return null;const o=h(e,n);if(!v(o))return null;const r=I(o);if(!r.isFile()||r.size>96*1024)return null;const c=f(o,"utf8");return{kind:"repo-path",path:n,contentHash:u(c).slice(0,16),mtimeMs:Math.floor(r.mtimeMs)}}function _(e){let t=e;const n=t;return t=t.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi,"[REDACTED_EMAIL]"),t=t.replace(/\b(api[-_ ]?key|license[-_ ]?key|token|password|secret)\b\s*[:=]\s*[^\s`'"\])}]+/gi,"$1=[REDACTED_SECRET]"),t=t.replace(/\b(?:sk|pk|ghp|github_pat|pat)_[A-Za-z0-9_\-]{16,}\b/g,"[REDACTED_TOKEN]"),t=t.replace(/\b[A-Za-z0-9+/]{32,}={0,2}\b/g,"[REDACTED_TOKEN]"),t=t.replace(/<!--\s*(?:server|private|proprietary)[\s\S]*?-->/gi,"[REDACTED_PRIVATE_PROMPT]"),t=t.replace(/\b(?:private|proprietary|protected)\s+(?:prompt|workflow|step\s*body|orchestration)\b[^.!?\n]*/gi,"[REDACTED_PRIVATE_PROMPT]"),{text:t,redacted:t!==n}}function R(e,t=y.maxSnippetChars){const n=e.split(/\r?\n/).map(r=>r.trim()).filter(r=>r.length>0&&!r.startsWith("---")&&!r.startsWith("<!--")).slice(0,8).join(" "),o=_(n);return{summary:o.text.slice(0,t),redacted:o.redacted}}function w(e,t){const n=k(e,t.path);if(!n)return null;const o=f(h(e,n.path),"utf8"),r=R(o,t.maxSnippetChars);return{nodeType:t.nodeType,stableId:t.stableId,source:n,confidence:r.redacted?Math.min(t.confidence,.72):t.confidence,reasonCode:t.reasonCode,budgetCost:t.budgetCost,summary:r.summary,warnings:r.redacted?["redacted_sensitive_content"]:void 0,score:t.score}}function S(e){const t=`Public command ${e.commandId}; graphRetrieval profile ${e.retrievalProfile}; context is auxiliary, redacted, budgeted and non-authoritative.`;return{nodeType:"Command",stableId:`command:${e.commandId}`,source:{kind:"command",path:e.commandId,contentHash:u(t).slice(0,16)},confidence:.88,reasonCode:"command_surface_match",budgetCost:1,summary:t.slice(0,e.retrievalBudget.maxSnippetChars),score:90}}function C(e){return e.match(/@?(docs\/stories\/[A-Za-z0-9._-]+\.story\.md)\b/)?.[1]??null}function $(e){return e.match(/@?(docs\/epics\/[A-Za-z0-9._-]+\.md)\b/)?.[1]??null}function D(e){const o=C(e)?.split("/").pop()?.replace(/\.story\.md$/,"")?.match(/^(P\d+)\./i)?.[1];if(o)return o.toUpperCase();const r=e.match(/\b(P\d+)(?:\.\d+)?\b/i)?.[1];return r?r.toUpperCase():null}function x(e){return[...e.matchAll(/@?(docs\/[A-Za-z0-9_./-]+\.md)\b/g)].map(t=>i(t[1])).filter(t=>!m(t))}function j(e){return e.startsWith("docs/stories/")?{nodeType:"Story",reasonCode:"story_scope_match"}:e.startsWith("docs/epics/")?{nodeType:"Epic",reasonCode:"epic_scope_match"}:e.includes("security")||e.includes("policy")||e.includes("standard")?{nodeType:"Guardrail",reasonCode:"guardrail_match"}:{nodeType:"Doc",reasonCode:"architecture_reference"}}function a(e,t){const n=i(t.path);if(m(n))return;e.some(r=>r.nodeType===t.nodeType&&i(r.path)===n)||e.push({...t,path:n})}function M(e,t,n){const o=C(t);if(o){const s=o.split("/").pop()?.replace(/\.story\.md$/,"")??o;a(e,{path:o,nodeType:"Story",stableId:s,reasonCode:"story_scope_match",confidence:.96,budgetCost:3,score:96,maxSnippetChars:n})}const r=$(t),c=D(t);if(r){const s=r.split("/").pop()?.replace(/\.md$/,"")??r;a(e,{path:r,nodeType:"Epic",stableId:s,reasonCode:"epic_scope_match",confidence:.92,budgetCost:3,score:92,maxSnippetChars:n})}else c&&a(e,{path:`docs/epics/epic-${c}.md`,nodeType:"Epic",stableId:c,reasonCode:"epic_scope_match",confidence:.9,budgetCost:3,score:90,maxSnippetChars:n});for(const s of x(t)){const l=s.split("/").pop()?.replace(/\.md$/,"").replace(/\.story$/,"")??s,d=j(s);a(e,{path:s,stableId:l,...d,confidence:.84,budgetCost:3,score:82,maxSnippetChars:n})}}function z(e,t,n){const o=e.retrievalBudget.maxSnippetChars,r=[];return a(r,{path:"NEOCORTEX.md",nodeType:"CanonicalMemory",stableId:"canonical-memory",reasonCode:"canonical_memory_seed",confidence:.92,budgetCost:4,score:100,maxSnippetChars:o}),a(r,{path:"AGENTS.md",nodeType:"PlatformMemory",stableId:"platform-memory:agents",reasonCode:"platform_memory_reference",confidence:.7,budgetCost:2,score:66,maxSnippetChars:o}),a(r,{path:"package.json",nodeType:"Package",stableId:"root-package",reasonCode:"package_surface_match",confidence:.78,budgetCost:2,score:72,maxSnippetChars:o}),(e.retrievalProfile!=="utility"||e.commandId==="ui-ux-review")&&a(r,{path:"docs/arquitetura-software/deterministic-graph-retrieval.md",nodeType:"Doc",stableId:"deterministic-graph-retrieval",reasonCode:"architecture_reference",confidence:.9,budgetCost:4,score:84,maxSnippetChars:o}),M(r,t,o),(["story-execution","diagnostic","research","review","qa","recovery","planning"].includes(e.retrievalProfile)||e.commandId==="tech-debt")&&a(r,{path:".neocortex/tech-debt-registry.json",nodeType:"Debt",stableId:"tech-debt-registry",reasonCode:"debt_area_match",confidence:.74,budgetCost:3,score:76,maxSnippetChars:o}),e.retrievalProfile==="security"&&a(r,{path:"docs/architecture/solyd-security-system-contract.md",nodeType:"Guardrail",stableId:"solyd-security-system-contract",reasonCode:"guardrail_match",confidence:.86,budgetCost:3,score:84,maxSnippetChars:o}),e.retrievalProfile==="continuity"&&a(r,{path:"docs/runbooks/enterprise-continuity-runner.md",nodeType:"Doc",stableId:"enterprise-continuity-runner",reasonCode:"architecture_reference",confidence:.78,budgetCost:3,score:72,maxSnippetChars:o}),["utility","continuity","recovery"].includes(e.retrievalProfile)&&a(r,{path:".neocortex/state.json",nodeType:"State",stableId:"project-state",reasonCode:"state_status_match",confidence:.68,budgetCost:3,score:70,maxSnippetChars:o}),[S(e),...r.map(c=>w(n,c)).filter(c=>c!==null)]}function G(e){let t=[...e.items],n=e;const o=Math.min(e.budget.maxPayloadBytes,y.maxPayloadBytes);for(;Buffer.byteLength(JSON.stringify(n),"utf8")>o&&t.length>0;){const r=t.pop(),c=g({retrievalId:e.retrievalId,query:e.query,items:t,generatedAt:e.generatedAt,warnings:e.warnings,budgets:e.budget});n={...c,skipped:r?[...c.skipped,{stableId:r.stableId,source:r.source,reasonCode:"budget_exceeded"}]:c.skipped,contractVersion:p,command:e.command}}return n}async function q(e){const t=b(e.args);if(!t)return{applied:!1,reason:"command_not_allowlisted"};const n=t.commandId;try{const o=z(t,e.args,e.projectRoot);if(o.length===0)return{applied:!1,reason:"no_items",command:n,profile:t.retrievalProfile};const r=_(e.args.trim().slice(0,240)).text,c=u(`${p}:${n}:${r}:${o.map(d=>`${d.source.path}:${d.source.contentHash??""}`).sort().join("|")}`).slice(0,24),s=g({retrievalId:c,query:r,items:o,generatedAt:e.nowIso??A,budgets:t.retrievalBudget}),l=G({...s,contractVersion:p,command:n});return{applied:!0,reason:"applied",command:n,profile:t.retrievalProfile,metadata:l}}catch(o){const r=o instanceof Error?o.message:String(o);return e.logger?.warn?.(`[neocortex] graph retrieval hook failed: ${r}. Proceeding without enrichment.`),{applied:!1,reason:"hook_error",command:n,profile:t.retrievalProfile,warning:r}}}async function F(e){if(e.enabled===!1)return{applied:!1,reason:"disabled"};const t=b(e.args);if(!t||!["arch-plan","ui-ux-review"].includes(t.commandId))return{applied:!1,reason:"command_not_supported"};try{return{applied:!0,reason:"applied",envelope:E({projectRoot:e.projectRoot,...e.nowIso?{collectedAt:e.nowIso}:{}})}}catch(n){const o=n instanceof Error?n.message:String(n);return e.logger?.warn?.("[neocortex] local project evidence collection failed; proceeding without project evidence."),{applied:!1,reason:"hook_error",warning:o}}}export{q as runGraphRetrievalHook,F as runProjectEvidenceHook};
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
/**
|
|
14
14
|
* @neocortex/client - Thin Client Abstraction Layer
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
* local filesystem (development) or remote server (production).
|
|
16
|
+
* Public-directive client with metadata-only remote capability resolution.
|
|
18
17
|
*
|
|
19
18
|
* @example
|
|
20
19
|
* ```typescript
|
|
@@ -31,17 +30,17 @@
|
|
|
31
30
|
* stepId: 'step-c-06-implement-tasks',
|
|
32
31
|
* });
|
|
33
32
|
*
|
|
34
|
-
* // Resolve
|
|
35
|
-
* const
|
|
33
|
+
* // Resolve public capability metadata. Protected asset bodies are unavailable.
|
|
34
|
+
* const registry = await resolver.resolveRegistry();
|
|
36
35
|
* ```
|
|
37
36
|
*/
|
|
38
|
-
export type {
|
|
37
|
+
export type { CacheOperationOptions, CacheProvider, CodebaseMetadata, CreateResolverOptions, PipelineContext, PublicCapabilityRegistry, PublicCapabilityRegistryEntry, RemoteResolverOptions, StoryMetadata, } from './types/index.js';
|
|
39
38
|
export { ResolverMode, NoOpCache } from './types/index.js';
|
|
40
|
-
export type
|
|
41
|
-
export {
|
|
42
|
-
export { RemoteResolver, RemoteResolverError } from './resolvers/remote-resolver.js';
|
|
39
|
+
export { PUBLIC_ARTIFACT_KINDS, PUBLIC_EXECUTION_ALLOWED_TOP_LEVEL_FIELDS, PUBLIC_EXECUTION_AUTHORITIES, PUBLIC_EXECUTION_CONTRACT_VERSION, PUBLIC_EXECUTION_DIRECTIVE_KINDS, PUBLIC_EXECUTION_LIMITS, PUBLIC_EXECUTION_MIN_SECURE_CLIENT_VERSION, PUBLIC_EXECUTION_NEGOTIATION_REASON_CODES, PUBLIC_EXECUTION_SCHEMA_HEADER, PUBLIC_EXECUTION_SCHEMA_VERSION, PUBLIC_EXECUTION_STATUSES, PUBLIC_EXECUTION_UNKNOWN_FIELD_POLICY, PUBLIC_EXECUTION_VALIDATION_REASON_CODES, PUBLIC_ROOT_EXECUTION_OPERATIONS, PUBLIC_SERVER_EXECUTION_OPERATIONS, PUBLIC_VALIDATION_STATUSES, PublicExecutionContractError, isPublicExecutionRepositoryPath, negotiatePublicExecutionSchema, serializePublicExecutionResponse, validatePublicExecutionResponse, type PublicArtifactKind, type PublicDirectiveAuthority, type PublicExecutionArtifact, type PublicExecutionAuthority, type PublicExecutionBlocker, type PublicExecutionDebt, type PublicExecutionDirective, type PublicExecutionNegotiationOptions, type PublicExecutionNegotiationReasonCode, type PublicExecutionNegotiationResult, type PublicExecutionRefs, type PublicExecutionResponse, type PublicExecutionStatus, type PublicExecutionUpgradeResponse, type PublicExecutionValidation, type PublicExecutionValidationIssue, type PublicExecutionValidationReasonCode, type PublicExecutionValidationResult, type PublicNativeTaskDirective, type PublicRootExecutionDirective, type PublicRootExecutionOperation, type PublicServerExecutionDirective, type PublicServerExecutionOperation, type PublicValidationStatus, } from './types/index.js';
|
|
40
|
+
export type { AssetResolver, PublicCapabilityResolver } from './resolvers/asset-resolver.js';
|
|
41
|
+
export { RemoteResolver, RemoteResolverError, validatePublicCapabilityRegistry, } from './resolvers/remote-resolver.js';
|
|
43
42
|
export { EncryptedCache, type EncryptedCacheOptions } from './cache/index.js';
|
|
44
|
-
export { createResolver, selectResolver, type ResolverSelectionResult, } from './config/resolver-selection.js';
|
|
43
|
+
export { createResolver, DevelopmentResolverUnavailableError, selectResolver, type ResolverSelectionResult, } from './config/resolver-selection.js';
|
|
45
44
|
export { collectContext, type CollectContextOptions, } from './context/context-collector.js';
|
|
46
45
|
export { sanitizeValue, sanitizeRecord, sanitizeObject, } from './context/context-sanitizer.js';
|
|
47
46
|
export { getMachineFingerprint } from './machine/index.js';
|
|
@@ -49,8 +48,8 @@ export { LicenseClient, type LicenseClientOptions } from './license/index.js';
|
|
|
49
48
|
export type { InjectionMethod, PlatformInstructions, TargetAdapter, TargetCapabilities, TargetConfig, DetectionContext, DetectionResult, FileExistsCheck, TargetId, } from './adapters/index.js';
|
|
50
49
|
export { ClaudeCodeAdapter, CursorAdapter, VSCodeAdapter, GeminiAdapter, CodexAdapter, AntigravityAdapter, AdapterRegistry, UnknownTargetError, createDefaultRegistry, detectPlatform, isValidTargetId, } from './adapters/index.js';
|
|
51
50
|
export { ClientCircuitBreaker, type CircuitState, type CircuitBreakerConfig, type CircuitBreakerState, DegradationManager, DegradationLevel, type DegradationContext, type DegradationDecision, FreshnessIndicator, type FreshnessInfo, RecoveryDetector, type RecoveryActions, type RecoveryResult, } from './resilience/index.js';
|
|
52
|
-
export { OfflineTelemetryQueue, type TelemetryEvent, type QueueConfig, type QueueStats, type FlushResult, } from './telemetry/index.js';
|
|
51
|
+
export { OfflineTelemetryQueue, validateTelemetryEvent, type TelemetryEvent, type QueueConfig, type QueueStats, type FlushResult, } from './telemetry/index.js';
|
|
53
52
|
export { getCacheStatus, formatCacheStatus, type CacheStatusInfo, type CacheStatusOptions, } from './commands/cache-status.js';
|
|
54
|
-
export { invoke, invokeCliHandler, collectStateSnapshot, type InvokeOptions, type InvokeResult, } from './commands/invoke.js';
|
|
53
|
+
export { invoke, invokeCliHandler, buildPublicExecutionRequestHeaders, collectStateSnapshot, dispatchPublicExecutionResponse, PublicExecutionResponseError, type InvokeOptions, type InvokeResult, type PublicExecutionDispatchMetadata, type PublicExecutionDispatchResult, type PublicExecutionTaskDirective, } from './commands/invoke.js';
|
|
55
54
|
export { TierAwareClient, type TierAwareClientOptions, type PreFlightResult, type QuotaSnapshot, } from './tier/index.js';
|
|
56
55
|
export { buildProjectMemoryContent, createNodeProjectMemoryFs, writeProjectMemory, writeProjectMemoryTargetFiles, type WriteProjectMemoryFileResult, type ProjectMemoryWriterFs, type WriteProjectMemoryOptions, type WriteProjectMemoryResult, type WriteProjectMemoryTargetFilesResult, } from './memory/project-memory-writer.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ResolverMode as t,NoOpCache as o}from"./types/index.js";import{
|
|
1
|
+
import{ResolverMode as t,NoOpCache as o}from"./types/index.js";import{PUBLIC_ARTIFACT_KINDS as i,PUBLIC_EXECUTION_ALLOWED_TOP_LEVEL_FIELDS as a,PUBLIC_EXECUTION_AUTHORITIES as C,PUBLIC_EXECUTION_CONTRACT_VERSION as I,PUBLIC_EXECUTION_DIRECTIVE_KINDS as _,PUBLIC_EXECUTION_LIMITS as c,PUBLIC_EXECUTION_MIN_SECURE_CLIENT_VERSION as n,PUBLIC_EXECUTION_NEGOTIATION_REASON_CODES as l,PUBLIC_EXECUTION_SCHEMA_HEADER as T,PUBLIC_EXECUTION_SCHEMA_VERSION as O,PUBLIC_EXECUTION_STATUSES as s,PUBLIC_EXECUTION_UNKNOWN_FIELD_POLICY as U,PUBLIC_EXECUTION_VALIDATION_REASON_CODES as p,PUBLIC_ROOT_EXECUTION_OPERATIONS as N,PUBLIC_SERVER_EXECUTION_OPERATIONS as P,PUBLIC_VALIDATION_STATUSES as R,PublicExecutionContractError as S,isPublicExecutionRepositoryPath as d,negotiatePublicExecutionSchema as m,serializePublicExecutionResponse as u,validatePublicExecutionResponse as L}from"./types/index.js";import{RemoteResolver as x,RemoteResolverError as f,validatePublicCapabilityRegistry as v}from"./resolvers/remote-resolver.js";import{EncryptedCache as D}from"./cache/index.js";import{createResolver as g,DevelopmentResolverUnavailableError as y,selectResolver as X}from"./config/resolver-selection.js";import{collectContext as V}from"./context/context-collector.js";import{sanitizeValue as F,sanitizeRecord as H,sanitizeObject as j}from"./context/context-sanitizer.js";import{getMachineFingerprint as w}from"./machine/index.js";import{LicenseClient as K}from"./license/index.js";import{ClaudeCodeAdapter as W,CursorAdapter as q,VSCodeAdapter as Q,GeminiAdapter as Y,CodexAdapter as J,AntigravityAdapter as Z,AdapterRegistry as $,UnknownTargetError as ee,createDefaultRegistry as re,detectPlatform as te,isValidTargetId as oe}from"./adapters/index.js";import{ClientCircuitBreaker as ie,DegradationManager as ae,DegradationLevel as Ce,FreshnessIndicator as Ie,RecoveryDetector as _e}from"./resilience/index.js";import{OfflineTelemetryQueue as ne,validateTelemetryEvent as le}from"./telemetry/index.js";import{getCacheStatus as Oe,formatCacheStatus as se}from"./commands/cache-status.js";import{invoke as pe,invokeCliHandler as Ne,buildPublicExecutionRequestHeaders as Pe,collectStateSnapshot as Re,dispatchPublicExecutionResponse as Se,PublicExecutionResponseError as de}from"./commands/invoke.js";import{TierAwareClient as ue}from"./tier/index.js";import{buildProjectMemoryContent as Ae,createNodeProjectMemoryFs as xe,writeProjectMemory as fe,writeProjectMemoryTargetFiles as ve}from"./memory/project-memory-writer.js";export{$ as AdapterRegistry,Z as AntigravityAdapter,W as ClaudeCodeAdapter,ie as ClientCircuitBreaker,J as CodexAdapter,q as CursorAdapter,Ce as DegradationLevel,ae as DegradationManager,y as DevelopmentResolverUnavailableError,D as EncryptedCache,Ie as FreshnessIndicator,Y as GeminiAdapter,K as LicenseClient,o as NoOpCache,ne as OfflineTelemetryQueue,i as PUBLIC_ARTIFACT_KINDS,a as PUBLIC_EXECUTION_ALLOWED_TOP_LEVEL_FIELDS,C as PUBLIC_EXECUTION_AUTHORITIES,I as PUBLIC_EXECUTION_CONTRACT_VERSION,_ as PUBLIC_EXECUTION_DIRECTIVE_KINDS,c as PUBLIC_EXECUTION_LIMITS,n as PUBLIC_EXECUTION_MIN_SECURE_CLIENT_VERSION,l as PUBLIC_EXECUTION_NEGOTIATION_REASON_CODES,T as PUBLIC_EXECUTION_SCHEMA_HEADER,O as PUBLIC_EXECUTION_SCHEMA_VERSION,s as PUBLIC_EXECUTION_STATUSES,U as PUBLIC_EXECUTION_UNKNOWN_FIELD_POLICY,p as PUBLIC_EXECUTION_VALIDATION_REASON_CODES,N as PUBLIC_ROOT_EXECUTION_OPERATIONS,P as PUBLIC_SERVER_EXECUTION_OPERATIONS,R as PUBLIC_VALIDATION_STATUSES,S as PublicExecutionContractError,de as PublicExecutionResponseError,_e as RecoveryDetector,x as RemoteResolver,f as RemoteResolverError,t as ResolverMode,ue as TierAwareClient,ee as UnknownTargetError,Q as VSCodeAdapter,Ae as buildProjectMemoryContent,Pe as buildPublicExecutionRequestHeaders,V as collectContext,Re as collectStateSnapshot,re as createDefaultRegistry,xe as createNodeProjectMemoryFs,g as createResolver,te as detectPlatform,Se as dispatchPublicExecutionResponse,se as formatCacheStatus,Oe as getCacheStatus,w as getMachineFingerprint,pe as invoke,Ne as invokeCliHandler,d as isPublicExecutionRepositoryPath,oe as isValidTargetId,m as negotiatePublicExecutionSchema,j as sanitizeObject,H as sanitizeRecord,F as sanitizeValue,X as selectResolver,u as serializePublicExecutionResponse,v as validatePublicCapabilityRegistry,L as validatePublicExecutionResponse,le as validateTelemetryEvent,fe as writeProjectMemory,ve as writeProjectMemoryTargetFiles};
|
|
@@ -30,6 +30,9 @@ export declare class LicenseClient {
|
|
|
30
30
|
private readonly machineId;
|
|
31
31
|
private token;
|
|
32
32
|
private refreshToken;
|
|
33
|
+
private getTokenFlight;
|
|
34
|
+
private activateFlight;
|
|
35
|
+
private refreshFlight;
|
|
33
36
|
constructor(options: LicenseClientOptions);
|
|
34
37
|
/**
|
|
35
38
|
* Get a valid JWT token. Checks memory, cache, refresh token, then activation.
|
|
@@ -44,12 +47,14 @@ export declare class LicenseClient {
|
|
|
44
47
|
* 6. activate() -> return
|
|
45
48
|
*/
|
|
46
49
|
getToken(): Promise<string | null>;
|
|
50
|
+
private getTokenInternal;
|
|
47
51
|
/**
|
|
48
52
|
* Activate the license by calling POST /api/v1/license/activate.
|
|
49
53
|
* Stores token and refresh_token in memory and cache on success.
|
|
50
54
|
* NEVER throws - returns null on failure.
|
|
51
55
|
*/
|
|
52
56
|
activate(): Promise<ActivationResult | null>;
|
|
57
|
+
private activateInternal;
|
|
53
58
|
/**
|
|
54
59
|
* Refresh using refresh_token by calling POST /api/v1/license/refresh.
|
|
55
60
|
* Sends refresh_token in body (no Authorization header needed).
|
|
@@ -62,6 +67,7 @@ export declare class LicenseClient {
|
|
|
62
67
|
* @param _currentToken - Deprecated. Kept for backward compat but ignored.
|
|
63
68
|
*/
|
|
64
69
|
refresh(_currentToken?: string): Promise<ActivationResult | null>;
|
|
70
|
+
private refreshInternal;
|
|
65
71
|
/**
|
|
66
72
|
* Force-refresh the token.
|
|
67
73
|
* Used when tier_changed is detected or a 401 response indicates the token is expired.
|
|
@@ -72,6 +78,17 @@ export declare class LicenseClient {
|
|
|
72
78
|
* Story 31.02: Uses refresh_token flow instead of JWT-based refresh.
|
|
73
79
|
*/
|
|
74
80
|
forceRefresh(): Promise<string | null>;
|
|
81
|
+
private fetchJsonBounded;
|
|
82
|
+
private createAuthGeneration;
|
|
83
|
+
private parseAuthGeneration;
|
|
84
|
+
private readAuthGeneration;
|
|
85
|
+
private loadAuthGeneration;
|
|
86
|
+
private persistAuthGeneration;
|
|
87
|
+
private applyAuthGeneration;
|
|
88
|
+
private toActivationResult;
|
|
89
|
+
private settleCacheWrites;
|
|
90
|
+
private runBoundedCacheOperation;
|
|
91
|
+
private waitForRotatedCredentials;
|
|
75
92
|
private checkTokenValidity;
|
|
76
93
|
private loadFromCache;
|
|
77
94
|
private loadRefreshTokenFromCache;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{decodeJwt as c}from"jose";import{NoOpCache as
|
|
1
|
+
import{decodeJwt as c}from"jose";import{randomUUID as f}from"node:crypto";import{NoOpCache as y}from"../types/index.js";import{getMachineFingerprint as k}from"../machine/fingerprint.js";const d="neocortex:jwt:token",p="neocortex:jwt:refresh_token",l="neocortex:auth:generation",g=300,u=10080*60*1e3,m="0.1.0",h=2e3,T=1e4,A=750,F=25;class O{serverUrl;licenseKey;cache;clientVersion;machineId;token=null;refreshToken=null;getTokenFlight=null;activateFlight=null;refreshFlight=null;constructor(e){this.serverUrl=e.serverUrl.replace(/\/+$/,""),this.licenseKey=e.licenseKey,this.cache=e.cacheProvider??new y,this.clientVersion=e.clientVersion??m,this.machineId=k()}async getToken(){if(this.getTokenFlight)return this.getTokenFlight;const e=this.getTokenInternal();return this.getTokenFlight=e,e.then(()=>{this.getTokenFlight===e&&(this.getTokenFlight=null)},()=>{this.getTokenFlight===e&&(this.getTokenFlight=null)}),e}async getTokenInternal(){try{if(this.token){const n=this.checkTokenValidity(this.token);if(n==="valid")return this.token;if(n==="needs-refresh")return(await this.refresh())?.token??this.token;this.token=null}const e=await this.loadAuthGeneration();if(e){this.applyAuthGeneration(e.state);const n=this.checkTokenValidity(e.state.jwt);if(n==="valid")return e.state.jwt;if(n==="needs-refresh")return(await this.refresh())?.token??e.state.jwt;this.token=null}if(this.refreshToken||(this.refreshToken=await this.loadRefreshTokenFromCache()),this.refreshToken){const n=await this.refresh();if(n?.token)return n.token}return(await this.activate())?.token??null}catch{return null}}async activate(){if(this.activateFlight)return this.activateFlight;const e=this.activateInternal();return this.activateFlight=e,e.then(()=>{this.activateFlight===e&&(this.activateFlight=null)},()=>{this.activateFlight===e&&(this.activateFlight=null)}),e}async activateInternal(){try{const e=await this.readAuthGeneration(),t=await this.fetchJsonBounded(`${this.serverUrl}/api/v1/license/activate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({license_key:this.licenseKey,machine_id:this.machineId,client_version:this.clientVersion})});if(!t?.response.ok||!t.data)return null;const n=t.data,i=this.createAuthGeneration(n.token,n.refresh_token,n.expires_in),a=(await this.persistAuthGeneration(i,e?.serialized??null))?.state??i;return this.applyAuthGeneration(a),this.toActivationResult(a)}catch{return null}}async refresh(e){if(this.refreshFlight)return this.refreshFlight;const t=this.refreshInternal();return this.refreshFlight=t,t.then(()=>{this.refreshFlight===t&&(this.refreshFlight=null)},()=>{this.refreshFlight===t&&(this.refreshFlight=null)}),t}async refreshInternal(){try{const e=await this.readAuthGeneration();e&&this.applyAuthGeneration(e.state);const t=e?.state.refresh??this.refreshToken??await this.loadRefreshTokenFromCache();if(!t)return null;const n=await this.fetchJsonBounded(`${this.serverUrl}/api/v1/license/refresh`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({refresh_token:t})});if(!n)return null;if(!n.response.ok){const o=await this.waitForRotatedCredentials(e?.state.generation??null,t);return o||(this.refreshToken===t&&(this.refreshToken=null),null)}if(!n.data)return null;const i=n.data,s=this.createAuthGeneration(i.token,i.refresh_token,i.expires_in),r=(await this.persistAuthGeneration(s,e?.serialized??null))?.state??s;return this.applyAuthGeneration(r),this.toActivationResult(r)}catch{return null}}async forceRefresh(){try{const e=await this.refresh();return e?.token?e.token:(this.token=null,this.refreshToken=null,(await this.activate())?.token??null)}catch{return null}}async fetchJsonBounded(e,t){const n=new AbortController;let i;const s=Promise.resolve().then(async()=>{const r=await fetch(e,{...t,signal:n.signal}),o=r.ok?await r.json():null;return{response:r,data:o}}).catch(()=>null),a=new Promise(r=>{i=setTimeout(()=>{n.abort(),r(null)},T)});try{return await Promise.race([s,a])}finally{n.abort(),i&&clearTimeout(i)}}createAuthGeneration(e,t,n){return{schema:1,generation:f(),jwt:e,refresh:t??null,expiresAt:Date.now()+Math.max(0,n)*1e3}}parseAuthGeneration(e){if(!e)return null;try{const t=JSON.parse(e);return t.schema!==1||typeof t.generation!="string"||typeof t.jwt!="string"||t.refresh!==null&&typeof t.refresh!="string"||typeof t.expiresAt!="number"||!Number.isFinite(t.expiresAt)?null:(c(t.jwt),{state:t,serialized:e})}catch{return null}}async readAuthGeneration(e=h){const t=await this.runBoundedCacheOperation(n=>this.cache.get(l,{signal:n}),null,e);return this.parseAuthGeneration(t)}async loadAuthGeneration(){const e=await this.readAuthGeneration();if(e)return e;const[t,n]=await Promise.all([this.loadFromCache(),this.loadRefreshTokenFromCache()]);if(!t)return null;try{const i=c(t).exp;if(!i)return null;const s={schema:1,generation:f(),jwt:t,refresh:n,expiresAt:i*1e3};return await this.persistAuthGeneration(s,null)??{state:s,serialized:JSON.stringify(s)}}catch{return null}}async persistAuthGeneration(e,t){const n=JSON.stringify(e);if(!await this.runBoundedCacheOperation(async r=>{if(this.cache.compareAndSet)return this.cache.compareAndSet(l,t,n,u,{signal:r});const o=await this.cache.get(l,{signal:r}),w=this.parseAuthGeneration(o)?.serialized??null;return r.aborted||w!==t?!1:(await this.cache.set(l,n,u,{signal:r}),!r.aborted)},!1)){const r=await this.readAuthGeneration();return r?.serialized!==t?r:null}const s=Math.max(1,Math.min(1440*60*1e3,e.expiresAt-Date.now())),a=[r=>this.cache.set(d,e.jwt,s,{signal:r})];return e.refresh&&a.push(r=>this.cache.set(p,e.refresh,u,{signal:r})),await this.settleCacheWrites(a),{state:e,serialized:n}}applyAuthGeneration(e){this.token=e.jwt,this.refreshToken=e.refresh}toActivationResult(e){return{token:e.jwt,expiresIn:Math.max(0,Math.ceil((e.expiresAt-Date.now())/1e3)),refreshToken:e.refresh??void 0}}async settleCacheWrites(e,t=h){await this.runBoundedCacheOperation(async n=>{await Promise.allSettled(e.map(i=>Promise.resolve().then(()=>i(n))))},void 0,t)}async runBoundedCacheOperation(e,t,n=h){const i=new AbortController;let s;const a=Promise.resolve().then(()=>e(i.signal)).catch(()=>t),r=new Promise(o=>{s=setTimeout(()=>{i.abort(),o(t)},n)});try{return await Promise.race([a,r])}finally{i.abort(),s&&clearTimeout(s)}}async waitForRotatedCredentials(e,t){const n=Date.now()+A;for(;Date.now()<n;){const i=n-Date.now(),s=await this.readAuthGeneration(Math.min(i,200));if(s&&s.state.generation!==e&&s.state.refresh!==t&&this.checkTokenValidity(s.state.jwt)!=="expired")return this.applyAuthGeneration(s.state),this.toActivationResult(s.state);const a=Math.min(F,n-Date.now());a>0&&await new Promise(r=>setTimeout(r,a))}return null}checkTokenValidity(e){try{const t=c(e);if(!t.exp)return"expired";const n=Math.floor(Date.now()/1e3);return t.exp<=n?"expired":t.exp-n<=g?"needs-refresh":"valid"}catch{return"expired"}}async loadFromCache(e=h){return this.runBoundedCacheOperation(t=>this.cache.get(d,{signal:t}),null,e)}async loadRefreshTokenFromCache(e=h){const t=await this.runBoundedCacheOperation(n=>this.cache.get(p,{signal:n}),null,e);return t&&t.length>0?t:null}}export{O as LicenseClient};
|