@smooai/smooth-operator-core 1.7.13 → 1.7.15

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/index.d.ts CHANGED
@@ -27,10 +27,12 @@ export { DenyPolicy, DenyRules, globMatch } from './denyPolicy.js';
27
27
  export type { DenyPredicate } from './denyPolicy.js';
28
28
  export { InMemoryKnowledge } from './knowledge.js';
29
29
  export type { Knowledge, KnowledgeHit } from './knowledge.js';
30
- export { MockLlmProvider, textResponse, toolCallResponse } from './llmProvider.js';
30
+ export { MockLlmProvider, SCRIPTED_USAGE, textResponse, toolCallResponse } from './llmProvider.js';
31
31
  export type { LlmProvider, RecordedCall, ScriptedMessage, ScriptedUsage } from './llmProvider.js';
32
32
  export { InMemoryMemory } from './memory.js';
33
33
  export type { Memory, MemoryEntry } from './memory.js';
34
+ export { hasInjection, hasSecrets, NarcHook, redactMatch, scanInjection, scanSecrets, Severity, severityLabel } from './narc.js';
35
+ export type { NarcAlert, NarcFinding } from './narc.js';
34
36
  export { LexicalReranker, NoopReranker } from './rerank.js';
35
37
  export type { Reranker } from './rerank.js';
36
38
  export { SmoothAgentThread } from './thread.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC3E,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC9K,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC/I,YAAY,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACjG,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,YAAY,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACzF,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC7F,OAAO,EACH,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,MAAM,EACN,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,YAAY,GACf,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC1E,YAAY,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACnG,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACjI,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC7D,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -16,8 +16,9 @@ export { AutoMode, autoModeFromEnv, autoModeFromValue, decide, domainMatchesSuff
16
16
  export { hostMatchesGlob, PermissionGrants } from './permissionGrants.js';
17
17
  export { DenyPolicy, DenyRules, globMatch } from './denyPolicy.js';
18
18
  export { InMemoryKnowledge } from './knowledge.js';
19
- export { MockLlmProvider, textResponse, toolCallResponse } from './llmProvider.js';
19
+ export { MockLlmProvider, SCRIPTED_USAGE, textResponse, toolCallResponse } from './llmProvider.js';
20
20
  export { InMemoryMemory } from './memory.js';
21
+ export { hasInjection, hasSecrets, NarcHook, redactMatch, scanInjection, scanSecrets, Severity, severityLabel } from './narc.js';
21
22
  export { LexicalReranker, NoopReranker } from './rerank.js';
22
23
  export { SmoothAgentThread } from './thread.js';
23
24
  export { MAX_MATCHES, TOOL_SEARCH_NAME, ToolSearch } from './toolSearch.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE/I,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEzF,OAAO,EACH,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,MAAM,EACN,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,YAAY,GACf,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEnF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE/I,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAEjG,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEzF,OAAO,EACH,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,MAAM,EACN,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,EACb,oBAAoB,EACpB,YAAY,GACf,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEnG,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEjI,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
@@ -57,6 +57,20 @@ export interface ScriptedUsage {
57
57
  prompt_tokens?: number;
58
58
  completion_tokens?: number;
59
59
  }
60
+ /**
61
+ * The token usage a **scripted** mock response reports. Fixed, and identical in
62
+ * all five engines' mocks (Rust · Go · Python · TypeScript · C#), so the shared
63
+ * server scenario corpus can assert `eventual_response.usage` as a real
64
+ * cross-language invariant instead of documenting five different answers
65
+ * (pearl th-4f1263).
66
+ *
67
+ * Only the FIFO scripting helpers ({@link MockLlmProvider.pushText} /
68
+ * {@link MockLlmProvider.pushToolCall}) attach it. An *unscripted* response — the
69
+ * benign empty reply a drained script falls back to — still reports nothing, so
70
+ * "the script ran out" stays distinguishable from "the model answered". Pass an
71
+ * explicit `usage` to override.
72
+ */
73
+ export declare const SCRIPTED_USAGE: Readonly<Required<ScriptedUsage>>;
60
74
  /**
61
75
  * A deterministic {@link LlmProvider} for tests. Script the responses it should
62
76
  * return (FIFO), drive your code, then assert on {@link MockLlmProvider.calls}.
@@ -78,9 +92,9 @@ export declare class MockLlmProvider implements ChatClientLike {
78
92
  constructor(script?: ScriptedMessage[]);
79
93
  /** Queue a raw OpenAI-shaped assistant message (with optional usage) for the next call. */
80
94
  pushResponse(message: ScriptedMessage, usage?: ScriptedUsage): this;
81
- /** Queue a plain-text response (with optional usage) for the next call. */
95
+ /** Queue a plain-text response for the next call, reporting {@link SCRIPTED_USAGE} unless `usage` overrides it. */
82
96
  pushText(content: string, usage?: ScriptedUsage): this;
83
- /** Queue a single-tool-call response (with optional usage) for the next call. */
97
+ /** Queue a single-tool-call response for the next call, reporting {@link SCRIPTED_USAGE} unless `usage` overrides it. */
84
98
  pushToolCall(id: string, name: string, args: string, usage?: ScriptedUsage): this;
85
99
  /** Queue an error to be thrown on the next call. */
86
100
  pushError(message: string): this;
@@ -1 +1 @@
1
- {"version":3,"file":"llmProvider.d.ts","sourceRoot":"","sources":["../src/llmProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC;AAEzC,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;CAC5F;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAE7D;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAExF;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IACzB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,wCAAwC;IACxC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,mDAAmD;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1C;AAED,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAKD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,YAAW,cAAc;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;gBAEnC,MAAM,GAAE,eAAe,EAAO;IAM1C,2FAA2F;IAC3F,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAKnE,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAItD,iFAAiF;IACjF,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAIjF,oDAAoD;IACpD,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOhC,4DAA4D;IAC5D,IAAI,KAAK,IAAI,SAAS,YAAY,EAAE,CAEnC;IAED,mCAAmC;IACnC,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,uCAAuC;IACvC,IAAI,QAAQ,IAAI,YAAY,GAAG,SAAS,CAEvC;IAID,OAAO,CAAC,MAAM;IAQd,QAAQ,CAAC,IAAI;;2BAEgB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;iCAcvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,aAAa,CAAC,SAAS,CAAC;;MAiC7E;CACL"}
1
+ {"version":3,"file":"llmProvider.d.ts","sourceRoot":"","sources":["../src/llmProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5D,2FAA2F;AAC3F,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC;AAEzC,qFAAqF;AACrF,MAAM,WAAW,eAAe;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;CAC5F;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAE7D;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAExF;AAED,8DAA8D;AAC9D,MAAM,WAAW,YAAY;IACzB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,wCAAwC;IACxC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACzC,mDAAmD;IACnD,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1C;AAED,4FAA4F;AAC5F,MAAM,WAAW,aAAa;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,CAA8D,CAAC;AAK5H;;;;;;;;;;;;;;GAcG;AACH,qBAAa,eAAgB,YAAW,cAAc;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;gBAEnC,MAAM,GAAE,eAAe,EAAO;IAM1C,2FAA2F;IAC3F,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAKnE,mHAAmH;IACnH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAItD,yHAAyH;IACzH,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI;IAIjF,oDAAoD;IACpD,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOhC,4DAA4D;IAC5D,IAAI,KAAK,IAAI,SAAS,YAAY,EAAE,CAEnC;IAED,mCAAmC;IACnC,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,uCAAuC;IACvC,IAAI,QAAQ,IAAI,YAAY,GAAG,SAAS,CAEvC;IAID,OAAO,CAAC,MAAM;IAQd,QAAQ,CAAC,IAAI;;2BAEgB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;iCAcvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,aAAa,CAAC,SAAS,CAAC;;MAiC7E;CACL"}
@@ -33,6 +33,20 @@ export function textResponse(content) {
33
33
  export function toolCallResponse(id, name, args) {
34
34
  return { content: null, tool_calls: [{ id, function: { name, arguments: args } }] };
35
35
  }
36
+ /**
37
+ * The token usage a **scripted** mock response reports. Fixed, and identical in
38
+ * all five engines' mocks (Rust · Go · Python · TypeScript · C#), so the shared
39
+ * server scenario corpus can assert `eventual_response.usage` as a real
40
+ * cross-language invariant instead of documenting five different answers
41
+ * (pearl th-4f1263).
42
+ *
43
+ * Only the FIFO scripting helpers ({@link MockLlmProvider.pushText} /
44
+ * {@link MockLlmProvider.pushToolCall}) attach it. An *unscripted* response — the
45
+ * benign empty reply a drained script falls back to — still reports nothing, so
46
+ * "the script ran out" stays distinguishable from "the model answered". Pass an
47
+ * explicit `usage` to override.
48
+ */
49
+ export const SCRIPTED_USAGE = Object.freeze({ prompt_tokens: 10, completion_tokens: 5 });
36
50
  /**
37
51
  * A deterministic {@link LlmProvider} for tests. Script the responses it should
38
52
  * return (FIFO), drive your code, then assert on {@link MockLlmProvider.calls}.
@@ -60,13 +74,13 @@ export class MockLlmProvider {
60
74
  this.script.push({ kind: 'message', message, usage });
61
75
  return this;
62
76
  }
63
- /** Queue a plain-text response (with optional usage) for the next call. */
77
+ /** Queue a plain-text response for the next call, reporting {@link SCRIPTED_USAGE} unless `usage` overrides it. */
64
78
  pushText(content, usage) {
65
- return this.pushResponse(textResponse(content), usage);
79
+ return this.pushResponse(textResponse(content), usage ?? SCRIPTED_USAGE);
66
80
  }
67
- /** Queue a single-tool-call response (with optional usage) for the next call. */
81
+ /** Queue a single-tool-call response for the next call, reporting {@link SCRIPTED_USAGE} unless `usage` overrides it. */
68
82
  pushToolCall(id, name, args, usage) {
69
- return this.pushResponse(toolCallResponse(id, name, args), usage);
83
+ return this.pushResponse(toolCallResponse(id, name, args), usage ?? SCRIPTED_USAGE);
70
84
  }
71
85
  /** Queue an error to be thrown on the next call. */
72
86
  pushError(message) {
@@ -1 +1 @@
1
- {"version":3,"file":"llmProvider.js","sourceRoot":"","sources":["../src/llmProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llmProvider.js","sourceRoot":"","sources":["../src/llmProvider.ts"],"names":[],"mappings":"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"}
package/dist/narc.d.ts ADDED
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Native secret-detection + prompt-injection scanning {@link ToolHook} — the
3
+ * TypeScript port of the Rust reference engine's `narc.rs` (pearl th-5f7227).
4
+ *
5
+ * The SEP extension host passes tool-call arguments to the extension subprocess
6
+ * **unscanned** and returns the subprocess's tool-result content to the model
7
+ * **verbatim**. Nothing at the extension boundary looks for leaked credentials or
8
+ * prompt-injection payloads. {@link NarcHook} closes that gap. It scans two things:
9
+ *
10
+ * - **Secrets** — 10 credential patterns (AWS keys, private keys, JWTs/bearer
11
+ * tokens, high-entropy provider keys, …).
12
+ * - **Prompt injection** — 8 patterns (instruction override, role hijack,
13
+ * jailbreak, data/URL exfiltration, …).
14
+ *
15
+ * ## Division of labour with `PermissionHook`
16
+ *
17
+ * The permission gate already owns the *dangerous-command* / *write* /
18
+ * *credential-path* circuit-breakers (`rm -rf /`, `curl | sh`, `~/.ssh/id_rsa`).
19
+ * Narc does **not** re-implement those — it is scoped to the one thing permission
20
+ * does not do: **content scanning of arguments and results** for secrets and
21
+ * injection. Install Narc *after* the permission hook so the allow/ask/deny
22
+ * decision happens first and Narc scans the calls that clear it.
23
+ *
24
+ * ## `preCall` (arguments) — blocks on exfiltration, alerts otherwise
25
+ *
26
+ * A {@link Severity.Block} injection match (the active data/URL exfiltration
27
+ * signals) throws, blocking the call before the tool runs. Lower-severity
28
+ * injection and any secret in the arguments are **alerted, not blocked** — a tool
29
+ * argument legitimately carrying a secret (writing a `.env`, configuring a
30
+ * client) is common enough that a hard block there would be a footgun.
31
+ *
32
+ * ## `postCall` (result) — detects, alerts, and **redacts** secrets
33
+ *
34
+ * `postCall` receives a **mutable** result, so a rewrite of `result.content` is
35
+ * what downstream consumers — and the LLM/conversation — actually see. A secret
36
+ * pattern in a tool result raises a {@link Severity.Block} alert *and* replaces
37
+ * the matched credential with `[REDACTED:<pattern-name>]` before it reaches the
38
+ * model. Injection patterns in the result remain detection + {@link Severity.Alert}
39
+ * only (surveillance) — they can appear in legitimate content and are not rewritten.
40
+ *
41
+ * The detection set is pinned across all five engines by the shared corpus at
42
+ * `spec/narc/corpus.json` (see `test/narc.test.ts`).
43
+ */
44
+ import type { ToolCall, ToolHook, ToolResult } from './agent.js';
45
+ /**
46
+ * Severity of a Narc finding, ordered least → most severe. A
47
+ * {@link Severity.Block} finding in `preCall` blocks the tool call. The numeric
48
+ * values ARE the ordering — compare with `>=`.
49
+ */
50
+ export declare enum Severity {
51
+ /** Informational — no action. */
52
+ Info = 0,
53
+ /** Suspicious but plausibly legitimate (e.g. a secret in an argument). */
54
+ Warn = 1,
55
+ /** Strong signal worth surfacing, but not auto-blocked. */
56
+ Alert = 2,
57
+ /** Actively harmful — blocks the call when raised in `preCall`. */
58
+ Block = 3
59
+ }
60
+ /** The shared wire label for a severity (`INFO`/`WARN`/`ALERT`/`BLOCK`). */
61
+ export declare function severityLabel(s: Severity): string;
62
+ /**
63
+ * A single surveillance finding. Lean by design — the consumer supplies the
64
+ * timestamp and correlation, so no uuid/timestamp fields are carried.
65
+ */
66
+ export interface NarcAlert {
67
+ /** How severe the finding is. */
68
+ severity: Severity;
69
+ /** Coarse bucket: `'injection'`, `'secret'`, `'secret_leak'`, `'injection_output'`. */
70
+ category: string;
71
+ /** The named pattern that matched. */
72
+ patternName: string;
73
+ /** Redacted view of the matched text (never the raw secret). */
74
+ redacted: string;
75
+ /** The tool whose args/result triggered the finding. */
76
+ toolName: string;
77
+ }
78
+ /** A pattern match: which pattern, its severity, and a redacted view. */
79
+ export interface NarcFinding {
80
+ /** The named pattern that matched. */
81
+ patternName: string;
82
+ /** The finding's severity. */
83
+ severity: Severity;
84
+ /** Redacted view of the matched text (safe to log). */
85
+ redacted: string;
86
+ }
87
+ /** Scan `text` for hardcoded secrets. Every match is redacted. */
88
+ export declare function scanSecrets(text: string): NarcFinding[];
89
+ /** Scan `text` for prompt-injection patterns. Matched text is redacted. */
90
+ export declare function scanInjection(text: string): NarcFinding[];
91
+ /** True if `text` contains any secret pattern. */
92
+ export declare function hasSecrets(text: string): boolean;
93
+ /** True if `text` contains any injection pattern. */
94
+ export declare function hasInjection(text: string): boolean;
95
+ /**
96
+ * Redact a matched string, showing only the first 4 and last 2 characters. Short
97
+ * matches (≤ 8 code points) are fully starred. Code points, not UTF-16 units —
98
+ * parity with the Rust reference's char-based redaction.
99
+ */
100
+ export declare function redactMatch(s: string): string;
101
+ /**
102
+ * A {@link ToolHook} that scans tool-call arguments and results for secrets and
103
+ * prompt injection. Install it via `AgentOptions.toolHooks` alongside the
104
+ * permission hook, *after* it.
105
+ *
106
+ * - **`preCall`** throws on a {@link Severity.Block} injection pattern in the
107
+ * arguments (active exfiltration); every other finding (lower-severity
108
+ * injection, any secret) is recorded as a {@link NarcAlert}, not blocked.
109
+ * - **`postCall`** detects secrets/injection in the result, records them, and
110
+ * **redacts** leaked secrets out of the content in place so the model never
111
+ * sees the raw credential.
112
+ */
113
+ export declare class NarcHook implements ToolHook {
114
+ private readonly log;
115
+ /** Snapshot every recorded alert. */
116
+ alerts(): NarcAlert[];
117
+ /** Recorded alerts at or above `minSeverity`. */
118
+ alertsAbove(minSeverity: Severity): NarcAlert[];
119
+ private record;
120
+ preCall(call: ToolCall): Promise<void>;
121
+ postCall(call: ToolCall, result: ToolResult): Promise<void>;
122
+ }
123
+ //# sourceMappingURL=narc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narc.d.ts","sourceRoot":"","sources":["../src/narc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjE;;;;GAIG;AACH,oBAAY,QAAQ;IAChB,iCAAiC;IACjC,IAAI,IAAI;IACR,0EAA0E;IAC1E,IAAI,IAAI;IACR,2DAA2D;IAC3D,KAAK,IAAI;IACT,mEAAmE;IACnE,KAAK,IAAI;CACZ;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAWjD;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACtB,iCAAiC;IACjC,QAAQ,EAAE,QAAQ,CAAC;IACnB,uFAAuF;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,yEAAyE;AACzE,MAAM,WAAW,WAAW;IACxB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,QAAQ,EAAE,QAAQ,CAAC;IACnB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;CACpB;AAsED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAEvD;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAEzD;AAED,kDAAkD;AAClD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,QAAS,YAAW,QAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAmB;IAEvC,qCAAqC;IACrC,MAAM,IAAI,SAAS,EAAE;IAIrB,iDAAiD;IACjD,WAAW,CAAC,WAAW,EAAE,QAAQ,GAAG,SAAS,EAAE;IAI/C,OAAO,CAAC,MAAM;IAIR,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBtC,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;CA6BpE"}
package/dist/narc.js ADDED
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Native secret-detection + prompt-injection scanning {@link ToolHook} — the
3
+ * TypeScript port of the Rust reference engine's `narc.rs` (pearl th-5f7227).
4
+ *
5
+ * The SEP extension host passes tool-call arguments to the extension subprocess
6
+ * **unscanned** and returns the subprocess's tool-result content to the model
7
+ * **verbatim**. Nothing at the extension boundary looks for leaked credentials or
8
+ * prompt-injection payloads. {@link NarcHook} closes that gap. It scans two things:
9
+ *
10
+ * - **Secrets** — 10 credential patterns (AWS keys, private keys, JWTs/bearer
11
+ * tokens, high-entropy provider keys, …).
12
+ * - **Prompt injection** — 8 patterns (instruction override, role hijack,
13
+ * jailbreak, data/URL exfiltration, …).
14
+ *
15
+ * ## Division of labour with `PermissionHook`
16
+ *
17
+ * The permission gate already owns the *dangerous-command* / *write* /
18
+ * *credential-path* circuit-breakers (`rm -rf /`, `curl | sh`, `~/.ssh/id_rsa`).
19
+ * Narc does **not** re-implement those — it is scoped to the one thing permission
20
+ * does not do: **content scanning of arguments and results** for secrets and
21
+ * injection. Install Narc *after* the permission hook so the allow/ask/deny
22
+ * decision happens first and Narc scans the calls that clear it.
23
+ *
24
+ * ## `preCall` (arguments) — blocks on exfiltration, alerts otherwise
25
+ *
26
+ * A {@link Severity.Block} injection match (the active data/URL exfiltration
27
+ * signals) throws, blocking the call before the tool runs. Lower-severity
28
+ * injection and any secret in the arguments are **alerted, not blocked** — a tool
29
+ * argument legitimately carrying a secret (writing a `.env`, configuring a
30
+ * client) is common enough that a hard block there would be a footgun.
31
+ *
32
+ * ## `postCall` (result) — detects, alerts, and **redacts** secrets
33
+ *
34
+ * `postCall` receives a **mutable** result, so a rewrite of `result.content` is
35
+ * what downstream consumers — and the LLM/conversation — actually see. A secret
36
+ * pattern in a tool result raises a {@link Severity.Block} alert *and* replaces
37
+ * the matched credential with `[REDACTED:<pattern-name>]` before it reaches the
38
+ * model. Injection patterns in the result remain detection + {@link Severity.Alert}
39
+ * only (surveillance) — they can appear in legitimate content and are not rewritten.
40
+ *
41
+ * The detection set is pinned across all five engines by the shared corpus at
42
+ * `spec/narc/corpus.json` (see `test/narc.test.ts`).
43
+ */
44
+ /**
45
+ * Severity of a Narc finding, ordered least → most severe. A
46
+ * {@link Severity.Block} finding in `preCall` blocks the tool call. The numeric
47
+ * values ARE the ordering — compare with `>=`.
48
+ */
49
+ export var Severity;
50
+ (function (Severity) {
51
+ /** Informational — no action. */
52
+ Severity[Severity["Info"] = 0] = "Info";
53
+ /** Suspicious but plausibly legitimate (e.g. a secret in an argument). */
54
+ Severity[Severity["Warn"] = 1] = "Warn";
55
+ /** Strong signal worth surfacing, but not auto-blocked. */
56
+ Severity[Severity["Alert"] = 2] = "Alert";
57
+ /** Actively harmful — blocks the call when raised in `preCall`. */
58
+ Severity[Severity["Block"] = 3] = "Block";
59
+ })(Severity || (Severity = {}));
60
+ /** The shared wire label for a severity (`INFO`/`WARN`/`ALERT`/`BLOCK`). */
61
+ export function severityLabel(s) {
62
+ switch (s) {
63
+ case Severity.Warn:
64
+ return 'WARN';
65
+ case Severity.Alert:
66
+ return 'ALERT';
67
+ case Severity.Block:
68
+ return 'BLOCK';
69
+ default:
70
+ return 'INFO';
71
+ }
72
+ }
73
+ /**
74
+ * The 10 secret patterns. All are {@link Severity.Warn} in arguments (may be
75
+ * legit) and escalate to {@link Severity.Block} when found in a result (a
76
+ * leak) — the caller decides which threshold to apply.
77
+ *
78
+ * Every regex carries `g` because the scanners enumerate **all** matches. That
79
+ * makes `RegExp.test` stateful on these objects, so this module never calls it —
80
+ * `hasSecrets`/`hasInjection` go through the scanners.
81
+ */
82
+ const SECRET_PATTERNS = [
83
+ { name: 'AWS Access Key', severity: Severity.Warn, regex: /AKIA[0-9A-Z]{16}/g },
84
+ { name: 'AWS Secret Key', severity: Severity.Warn, regex: /aws[_\-]?secret[_\-]?access[_\-]?key\s*[=:]\s*[A-Za-z0-9/+=]{40}/gi },
85
+ { name: 'Anthropic API Key', severity: Severity.Warn, regex: /sk-ant-[A-Za-z0-9\-_]{20,}/g },
86
+ { name: 'OpenAI API Key', severity: Severity.Warn, regex: /sk-[A-Za-z0-9]{20,}/g },
87
+ { name: 'GitHub Token', severity: Severity.Warn, regex: /gh[posr]_[A-Za-z0-9_]{36,}/g },
88
+ { name: 'Private Key', severity: Severity.Warn, regex: /-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----/g },
89
+ { name: 'Generic Secret', severity: Severity.Warn, regex: /(secret|password|token|api[_\-]?key)\s*[=:]\s*["']?[A-Za-z0-9/+=\-_]{8,}/gi },
90
+ { name: 'Bearer Token', severity: Severity.Warn, regex: /Bearer\s+[A-Za-z0-9\-_.~+/]+=*/g },
91
+ { name: 'Base64 Encoded Key', severity: Severity.Warn, regex: /(key|secret|password)\s*[=:]\s*[A-Za-z0-9+/]{32,}={0,2}/gi },
92
+ { name: 'Stripe Key', severity: Severity.Warn, regex: /[sr]k_(live|test)_[A-Za-z0-9]{20,}/g },
93
+ ];
94
+ /**
95
+ * The 8 injection patterns. Only the active data/URL exfiltration signals are
96
+ * {@link Severity.Block} (blocked in arguments); hijack/jailbreak text is
97
+ * {@link Severity.Alert} (surveilled, not blocked — it can appear in legitimate
98
+ * content the model is authoring, e.g. a security test or documentation about
99
+ * injection).
100
+ *
101
+ * `data_exfiltration` is the Rust pattern's free-spacing `(?x)` form flattened to
102
+ * one line: JavaScript has no `x` flag, and a rewrite that dropped an alternative
103
+ * would silently weaken the detector.
104
+ */
105
+ const INJECTION_PATTERNS = [
106
+ { name: 'ignore_instructions', severity: Severity.Alert, regex: /ignore\s+(all\s+)?(previous|prior|above)\s+(instructions|prompts|rules)/gi },
107
+ { name: 'role_hijack', severity: Severity.Alert, regex: /(you\s+are\s+now|act\s+as|pretend\s+(to\s+be|you\s+are)|from\s+now\s+on\s+you\s+are)/gi },
108
+ { name: 'system_prompt', severity: Severity.Alert, regex: /(system\s*:\s*|<\|system\|>|\[SYSTEM\])/gi },
109
+ { name: 'jailbreak', severity: Severity.Alert, regex: /(DAN\s+mode|developer\s+mode|do\s+anything\s+now|jailbreak)/gi },
110
+ { name: 'base64_smuggling', severity: Severity.Alert, regex: /(decode|eval|execute)\s+(this\s+)?(base64|encoded)/gi },
111
+ {
112
+ name: 'data_exfiltration',
113
+ severity: Severity.Block,
114
+ regex: /(send|post|upload|exfiltrate|transmit|leak|push)\s+(all\s+|the\s+|our\s+|my\s+|this\s+)*(data|files?|secrets?|credentials?|keys?|tokens?|contents?|env\s+(vars?|file)|package\.json|\.env|pyproject\.toml|cargo\.toml|requirements\.txt|gemfile|go\.mod|composer\.json|\.ssh\/[a-z_]+|id_rsa|\.aws\/[a-z]+|\.gnupg\/)\s+(to|via|at|over)/gi,
115
+ },
116
+ {
117
+ name: 'url_exfiltration',
118
+ severity: Severity.Block,
119
+ regex: /(send|post|upload|push|transmit|leak|exfiltrate)\b[^.\n]{1,200}\s+(to|via|at|over)\s+(https?:\/\/[\w.\-/]+)/gi,
120
+ },
121
+ { name: 'smell_url', severity: Severity.Alert, regex: /https?:\/\/[\w.\-]*\b(leak|exfil|attacker|evil|tracker|c2(?:server)?|webhook\.site)\b[\w.\-/]*/gi },
122
+ ];
123
+ function scan(patterns, text) {
124
+ const out = [];
125
+ for (const p of patterns) {
126
+ for (const m of text.matchAll(p.regex)) {
127
+ out.push({ patternName: p.name, severity: p.severity, redacted: redactMatch(m[0]) });
128
+ }
129
+ }
130
+ return out;
131
+ }
132
+ /** Scan `text` for hardcoded secrets. Every match is redacted. */
133
+ export function scanSecrets(text) {
134
+ return scan(SECRET_PATTERNS, text);
135
+ }
136
+ /** Scan `text` for prompt-injection patterns. Matched text is redacted. */
137
+ export function scanInjection(text) {
138
+ return scan(INJECTION_PATTERNS, text);
139
+ }
140
+ /** True if `text` contains any secret pattern. */
141
+ export function hasSecrets(text) {
142
+ return scanSecrets(text).length > 0;
143
+ }
144
+ /** True if `text` contains any injection pattern. */
145
+ export function hasInjection(text) {
146
+ return scanInjection(text).length > 0;
147
+ }
148
+ /**
149
+ * Redact a matched string, showing only the first 4 and last 2 characters. Short
150
+ * matches (≤ 8 code points) are fully starred. Code points, not UTF-16 units —
151
+ * parity with the Rust reference's char-based redaction.
152
+ */
153
+ export function redactMatch(s) {
154
+ const chars = [...s];
155
+ if (chars.length <= 8)
156
+ return '*'.repeat(chars.length);
157
+ return chars.slice(0, 4).join('') + '*'.repeat(chars.length - 6) + '**' + chars.slice(chars.length - 2).join('');
158
+ }
159
+ /**
160
+ * A {@link ToolHook} that scans tool-call arguments and results for secrets and
161
+ * prompt injection. Install it via `AgentOptions.toolHooks` alongside the
162
+ * permission hook, *after* it.
163
+ *
164
+ * - **`preCall`** throws on a {@link Severity.Block} injection pattern in the
165
+ * arguments (active exfiltration); every other finding (lower-severity
166
+ * injection, any secret) is recorded as a {@link NarcAlert}, not blocked.
167
+ * - **`postCall`** detects secrets/injection in the result, records them, and
168
+ * **redacts** leaked secrets out of the content in place so the model never
169
+ * sees the raw credential.
170
+ */
171
+ export class NarcHook {
172
+ log = [];
173
+ /** Snapshot every recorded alert. */
174
+ alerts() {
175
+ return [...this.log];
176
+ }
177
+ /** Recorded alerts at or above `minSeverity`. */
178
+ alertsAbove(minSeverity) {
179
+ return this.log.filter((a) => a.severity >= minSeverity);
180
+ }
181
+ record(alert) {
182
+ this.log.push(alert);
183
+ }
184
+ async preCall(call) {
185
+ const argsText = JSON.stringify(call.arguments);
186
+ // Scan all first so every finding is recorded even when one of them blocks.
187
+ let block;
188
+ for (const f of scanInjection(argsText)) {
189
+ if (f.severity >= Severity.Block && block === undefined)
190
+ block = f;
191
+ this.record({ severity: f.severity, category: 'injection', patternName: f.patternName, redacted: f.redacted, toolName: call.name });
192
+ }
193
+ // Secrets in arguments: alert only (may be legitimate).
194
+ for (const f of scanSecrets(argsText)) {
195
+ this.record({ severity: f.severity, category: 'secret', patternName: f.patternName, redacted: f.redacted, toolName: call.name });
196
+ }
197
+ if (block !== undefined) {
198
+ throw new Error(`prompt-injection pattern \`${block.patternName}\` in tool arguments — blocked`);
199
+ }
200
+ }
201
+ async postCall(call, result) {
202
+ // A secret in a tool result is a leak. Record a Block alert AND redact it
203
+ // out of `result.content` — the mutable seam means this rewrite is what
204
+ // the model/conversation and every downstream consumer actually see.
205
+ const secrets = scanSecrets(result.content);
206
+ for (const f of secrets) {
207
+ this.record({ severity: Severity.Block, category: 'secret_leak', patternName: f.patternName, redacted: f.redacted, toolName: call.name });
208
+ }
209
+ if (secrets.length > 0) {
210
+ let content = result.content;
211
+ for (const p of SECRET_PATTERNS) {
212
+ // Replace via a function so `$&`-style sequences in a pattern name
213
+ // could never be interpolated into the output.
214
+ content = content.replace(p.regex, () => `[REDACTED:${p.name}]`);
215
+ }
216
+ result.content = content;
217
+ }
218
+ // Injection in the result is detection + alert only (surveillance) — scan
219
+ // the post-redaction content the model will actually see.
220
+ for (const f of scanInjection(result.content)) {
221
+ this.record({
222
+ severity: f.severity > Severity.Alert ? f.severity : Severity.Alert,
223
+ category: 'injection_output',
224
+ patternName: f.patternName,
225
+ redacted: f.redacted,
226
+ toolName: call.name,
227
+ });
228
+ }
229
+ }
230
+ }
231
+ //# sourceMappingURL=narc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narc.js","sourceRoot":"","sources":["../src/narc.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smooai/smooth-operator-core",
3
- "version": "1.7.13",
3
+ "version": "1.7.15",
4
4
  "description": "Native TypeScript implementation of the smooth-operator agent engine — an in-process, OpenAI-compatible agentic tool-calling loop with knowledge grounding. The TypeScript sibling of the Rust reference engine, the C# core, and the Python core.",
5
5
  "type": "module",
6
6
  "license": "MIT",