@cdot65/daystrom 1.0.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.
Files changed (134) hide show
  1. package/README.md +93 -0
  2. package/dist/airs/management.d.ts +21 -0
  3. package/dist/airs/management.d.ts.map +1 -0
  4. package/dist/airs/management.js +78 -0
  5. package/dist/airs/management.js.map +1 -0
  6. package/dist/airs/scanner.d.ts +8 -0
  7. package/dist/airs/scanner.d.ts.map +1 -0
  8. package/dist/airs/scanner.js +28 -0
  9. package/dist/airs/scanner.js.map +1 -0
  10. package/dist/airs/types.d.ts +26 -0
  11. package/dist/airs/types.d.ts.map +1 -0
  12. package/dist/airs/types.js +6 -0
  13. package/dist/airs/types.js.map +1 -0
  14. package/dist/cli/commands/generate.d.ts +3 -0
  15. package/dist/cli/commands/generate.d.ts.map +1 -0
  16. package/dist/cli/commands/generate.js +127 -0
  17. package/dist/cli/commands/generate.js.map +1 -0
  18. package/dist/cli/commands/list.d.ts +3 -0
  19. package/dist/cli/commands/list.d.ts.map +1 -0
  20. package/dist/cli/commands/list.js +22 -0
  21. package/dist/cli/commands/list.js.map +1 -0
  22. package/dist/cli/commands/report.d.ts +3 -0
  23. package/dist/cli/commands/report.d.ts.map +1 -0
  24. package/dist/cli/commands/report.js +57 -0
  25. package/dist/cli/commands/report.js.map +1 -0
  26. package/dist/cli/commands/resume.d.ts +3 -0
  27. package/dist/cli/commands/resume.d.ts.map +1 -0
  28. package/dist/cli/commands/resume.js +95 -0
  29. package/dist/cli/commands/resume.js.map +1 -0
  30. package/dist/cli/index.d.ts +3 -0
  31. package/dist/cli/index.d.ts.map +1 -0
  32. package/dist/cli/index.js +18 -0
  33. package/dist/cli/index.js.map +1 -0
  34. package/dist/cli/prompts.d.ts +6 -0
  35. package/dist/cli/prompts.d.ts.map +1 -0
  36. package/dist/cli/prompts.js +72 -0
  37. package/dist/cli/prompts.js.map +1 -0
  38. package/dist/cli/renderer.d.ts +15 -0
  39. package/dist/cli/renderer.d.ts.map +1 -0
  40. package/dist/cli/renderer.js +103 -0
  41. package/dist/cli/renderer.js.map +1 -0
  42. package/dist/config/loader.d.ts +3 -0
  43. package/dist/config/loader.d.ts.map +1 -0
  44. package/dist/config/loader.js +63 -0
  45. package/dist/config/loader.js.map +1 -0
  46. package/dist/config/schema.d.ts +72 -0
  47. package/dist/config/schema.d.ts.map +1 -0
  48. package/dist/config/schema.js +42 -0
  49. package/dist/config/schema.js.map +1 -0
  50. package/dist/core/constraints.d.ts +16 -0
  51. package/dist/core/constraints.d.ts.map +1 -0
  52. package/dist/core/constraints.js +77 -0
  53. package/dist/core/constraints.js.map +1 -0
  54. package/dist/core/loop.d.ts +23 -0
  55. package/dist/core/loop.d.ts.map +1 -0
  56. package/dist/core/loop.js +146 -0
  57. package/dist/core/loop.js.map +1 -0
  58. package/dist/core/metrics.d.ts +3 -0
  59. package/dist/core/metrics.d.ts.map +1 -0
  60. package/dist/core/metrics.js +38 -0
  61. package/dist/core/metrics.js.map +1 -0
  62. package/dist/core/types.d.ts +104 -0
  63. package/dist/core/types.d.ts.map +1 -0
  64. package/dist/core/types.js +5 -0
  65. package/dist/core/types.js.map +1 -0
  66. package/dist/index.d.ts +23 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +34 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/llm/prompts/analyze-results.d.ts +3 -0
  71. package/dist/llm/prompts/analyze-results.d.ts.map +1 -0
  72. package/dist/llm/prompts/analyze-results.js +38 -0
  73. package/dist/llm/prompts/analyze-results.js.map +1 -0
  74. package/dist/llm/prompts/generate-tests.d.ts +3 -0
  75. package/dist/llm/prompts/generate-tests.d.ts.map +1 -0
  76. package/dist/llm/prompts/generate-tests.js +33 -0
  77. package/dist/llm/prompts/generate-tests.js.map +1 -0
  78. package/dist/llm/prompts/generate-topic.d.ts +4 -0
  79. package/dist/llm/prompts/generate-topic.d.ts.map +1 -0
  80. package/dist/llm/prompts/generate-topic.js +32 -0
  81. package/dist/llm/prompts/generate-topic.js.map +1 -0
  82. package/dist/llm/prompts/improve-topic.d.ts +3 -0
  83. package/dist/llm/prompts/improve-topic.d.ts.map +1 -0
  84. package/dist/llm/prompts/improve-topic.js +50 -0
  85. package/dist/llm/prompts/improve-topic.js.map +1 -0
  86. package/dist/llm/provider.d.ts +15 -0
  87. package/dist/llm/provider.d.ts.map +1 -0
  88. package/dist/llm/provider.js +71 -0
  89. package/dist/llm/provider.js.map +1 -0
  90. package/dist/llm/schemas.d.ts +97 -0
  91. package/dist/llm/schemas.d.ts.map +1 -0
  92. package/dist/llm/schemas.js +22 -0
  93. package/dist/llm/schemas.js.map +1 -0
  94. package/dist/llm/service.d.ts +19 -0
  95. package/dist/llm/service.d.ts.map +1 -0
  96. package/dist/llm/service.js +177 -0
  97. package/dist/llm/service.js.map +1 -0
  98. package/dist/memory/diff.d.ts +4 -0
  99. package/dist/memory/diff.d.ts.map +1 -0
  100. package/dist/memory/diff.js +24 -0
  101. package/dist/memory/diff.js.map +1 -0
  102. package/dist/memory/extractor.d.ts +15 -0
  103. package/dist/memory/extractor.d.ts.map +1 -0
  104. package/dist/memory/extractor.js +129 -0
  105. package/dist/memory/extractor.js.map +1 -0
  106. package/dist/memory/injector.d.ts +8 -0
  107. package/dist/memory/injector.d.ts.map +1 -0
  108. package/dist/memory/injector.js +76 -0
  109. package/dist/memory/injector.js.map +1 -0
  110. package/dist/memory/prompts/extract-learnings.d.ts +3 -0
  111. package/dist/memory/prompts/extract-learnings.d.ts.map +1 -0
  112. package/dist/memory/prompts/extract-learnings.js +34 -0
  113. package/dist/memory/prompts/extract-learnings.js.map +1 -0
  114. package/dist/memory/schemas.d.ts +63 -0
  115. package/dist/memory/schemas.d.ts.map +1 -0
  116. package/dist/memory/schemas.js +13 -0
  117. package/dist/memory/schemas.js.map +1 -0
  118. package/dist/memory/store.d.ts +13 -0
  119. package/dist/memory/store.d.ts.map +1 -0
  120. package/dist/memory/store.js +88 -0
  121. package/dist/memory/store.js.map +1 -0
  122. package/dist/memory/types.d.ts +55 -0
  123. package/dist/memory/types.d.ts.map +1 -0
  124. package/dist/memory/types.js +6 -0
  125. package/dist/memory/types.js.map +1 -0
  126. package/dist/persistence/store.d.ts +12 -0
  127. package/dist/persistence/store.d.ts.map +1 -0
  128. package/dist/persistence/store.js +68 -0
  129. package/dist/persistence/store.js.map +1 -0
  130. package/dist/persistence/types.d.ts +17 -0
  131. package/dist/persistence/types.d.ts.map +1 -0
  132. package/dist/persistence/types.js +2 -0
  133. package/dist/persistence/types.js.map +1 -0
  134. package/package.json +65 -0
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # Daystrom
2
+
3
+ [![CI](https://github.com/cdot65/daystrom/actions/workflows/ci.yml/badge.svg)](https://github.com/cdot65/daystrom/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node 20+](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org/)
6
+
7
+ **Automated CLI that generates, tests, and iteratively refines Palo Alto Prisma AIRS custom topic guardrails.**
8
+
9
+ Daystrom uses an LLM to produce topic definitions, deploys them to Prisma AIRS, scans test prompts, evaluates efficacy, and loops until a coverage target is met. Cross-run memory persists learnings for future runs.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install -g daystrom
15
+ ```
16
+
17
+ Requires **Node.js >= 20**.
18
+
19
+ ### Docker
20
+
21
+ ```bash
22
+ docker run --rm --env-file .env \
23
+ -v ~/.daystrom:/root/.daystrom \
24
+ ghcr.io/cdot65/daystrom generate \
25
+ --profile my-security-profile \
26
+ --topic "Block discussions about building explosives" \
27
+ --intent block
28
+ ```
29
+
30
+ ## Configure
31
+
32
+ Copy `.env.example` or export directly:
33
+
34
+ ```bash
35
+ # LLM (default: claude-api)
36
+ export ANTHROPIC_API_KEY=sk-ant-...
37
+
38
+ # Prisma AIRS Scan API
39
+ export PANW_AI_SEC_API_KEY=your-scan-api-key
40
+
41
+ # Prisma AIRS Management API (OAuth2)
42
+ export PANW_MGMT_CLIENT_ID=your-client-id
43
+ export PANW_MGMT_CLIENT_SECRET=your-client-secret
44
+ export PANW_MGMT_TSG_ID=your-tsg-id
45
+ ```
46
+
47
+ Six LLM providers supported: `claude-api`, `claude-vertex`, `claude-bedrock`, `gemini-api`, `gemini-vertex`, `gemini-bedrock`. See [Configuration](https://cdot65.github.io/daystrom/getting-started/configuration/) for all options.
48
+
49
+ ## Usage
50
+
51
+ ```bash
52
+ # Interactive — prompts for topic, profile, intent
53
+ daystrom generate
54
+
55
+ # Non-interactive
56
+ daystrom generate \
57
+ --provider claude-api \
58
+ --profile my-security-profile \
59
+ --topic "Block discussions about building explosives" \
60
+ --intent block \
61
+ --target-coverage 90
62
+ ```
63
+
64
+ ### Commands
65
+
66
+ | Command | Description |
67
+ |---------|-------------|
68
+ | `daystrom generate` | Start a new guardrail generation loop |
69
+ | `daystrom resume <runId>` | Resume a paused or failed run |
70
+ | `daystrom report <runId>` | View results for a saved run |
71
+ | `daystrom list` | List all saved runs |
72
+
73
+ ## Development
74
+
75
+ ```bash
76
+ git clone git@github.com:cdot65/daystrom.git
77
+ cd daystrom
78
+ pnpm install
79
+ cp .env.example .env # edit with your credentials
80
+ pnpm run generate # run via tsx
81
+ pnpm test # 192 tests
82
+ pnpm run lint # biome check
83
+ ```
84
+
85
+ ## Documentation
86
+
87
+ Full docs — architecture, providers, memory system, metrics, and more:
88
+
89
+ **[cdot65.github.io/daystrom](https://cdot65.github.io/daystrom/)**
90
+
91
+ ## License
92
+
93
+ MIT
@@ -0,0 +1,21 @@
1
+ import { type CreateCustomTopicRequest, type ManagementClientOptions, type CustomTopic as SdkCustomTopic } from '@cdot65/prisma-airs-sdk';
2
+ import type { ManagementService } from './types.js';
3
+ /**
4
+ * Wraps the SDK's ManagementClient to implement our ManagementService interface.
5
+ * OAuth2 token management, caching, and retry are handled by the SDK.
6
+ */
7
+ export declare class SdkManagementService implements ManagementService {
8
+ private client;
9
+ constructor(opts?: ManagementClientOptions);
10
+ createTopic(request: CreateCustomTopicRequest): Promise<SdkCustomTopic>;
11
+ updateTopic(topicId: string, request: CreateCustomTopicRequest): Promise<SdkCustomTopic>;
12
+ deleteTopic(topicId: string): Promise<void>;
13
+ listTopics(): Promise<SdkCustomTopic[]>;
14
+ /**
15
+ * Sets a single custom topic on a profile's topic-guardrails config.
16
+ * Replaces any existing topics so only the current topic is evaluated.
17
+ * Previous runs may have left stale topics — this clears them.
18
+ */
19
+ assignTopicToProfile(profileName: string, topicId: string, topicName: string, action: 'allow' | 'block'): Promise<void>;
20
+ }
21
+ //# sourceMappingURL=management.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"management.d.ts","sourceRoot":"","sources":["../../src/airs/management.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,wBAAwB,EAE7B,KAAK,uBAAuB,EAC5B,KAAK,WAAW,IAAI,cAAc,EACnC,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,iBAAiB;IAC5D,OAAO,CAAC,MAAM,CAAmB;gBAErB,IAAI,CAAC,EAAE,uBAAuB;IAIpC,WAAW,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,cAAc,CAAC;IAIvE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,cAAc,CAAC;IAIxF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC;IAK7C;;;;OAIG;IACG,oBAAoB,CACxB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,GAAG,OAAO,GACxB,OAAO,CAAC,IAAI,CAAC;CAsDjB"}
@@ -0,0 +1,78 @@
1
+ import { ManagementClient, } from '@cdot65/prisma-airs-sdk';
2
+ /**
3
+ * Wraps the SDK's ManagementClient to implement our ManagementService interface.
4
+ * OAuth2 token management, caching, and retry are handled by the SDK.
5
+ */
6
+ export class SdkManagementService {
7
+ client;
8
+ constructor(opts) {
9
+ this.client = new ManagementClient(opts);
10
+ }
11
+ async createTopic(request) {
12
+ return this.client.topics.create(request);
13
+ }
14
+ async updateTopic(topicId, request) {
15
+ return this.client.topics.update(topicId, request);
16
+ }
17
+ async deleteTopic(topicId) {
18
+ await this.client.topics.delete(topicId);
19
+ }
20
+ async listTopics() {
21
+ const response = await this.client.topics.list();
22
+ return response.custom_topics;
23
+ }
24
+ /**
25
+ * Sets a single custom topic on a profile's topic-guardrails config.
26
+ * Replaces any existing topics so only the current topic is evaluated.
27
+ * Previous runs may have left stale topics — this clears them.
28
+ */
29
+ async assignTopicToProfile(profileName, topicId, topicName, action) {
30
+ // Find profile by name
31
+ const { ai_profiles } = await this.client.profiles.list();
32
+ const profile = ai_profiles.find((p) => p.profile_name === profileName);
33
+ if (!profile?.profile_id) {
34
+ throw new Error(`Profile "${profileName}" not found`);
35
+ }
36
+ // Deep clone the policy to mutate
37
+ const policy = JSON.parse(JSON.stringify(profile.policy ?? {}));
38
+ const aiProfiles = policy['ai-security-profiles'] ?? [
39
+ { 'model-type': 'default', 'model-configuration': {} },
40
+ ];
41
+ const modelConfig = aiProfiles[0]?.['model-configuration'] ?? {};
42
+ // Find or create model-protection with topic-guardrails
43
+ const modelProtection = modelConfig['model-protection'] ?? [];
44
+ let topicGuardrails = modelProtection.find((mp) => mp.name === 'topic-guardrails');
45
+ if (!topicGuardrails) {
46
+ topicGuardrails = {
47
+ action: 'allow',
48
+ name: 'topic-guardrails',
49
+ options: [],
50
+ 'topic-list': [],
51
+ };
52
+ modelProtection.push(topicGuardrails);
53
+ }
54
+ // Replace the entire topic-list with only the current topic under the given action.
55
+ // The opposite action gets an empty list to ensure no stale topics remain.
56
+ const oppositeAction = action === 'block' ? 'allow' : 'block';
57
+ topicGuardrails['topic-list'] = [
58
+ {
59
+ action,
60
+ topic: [{ topic_id: topicId, topic_name: topicName, revision: 1 }],
61
+ },
62
+ {
63
+ action: oppositeAction,
64
+ topic: [],
65
+ },
66
+ ];
67
+ // Write back
68
+ modelConfig['model-protection'] = modelProtection;
69
+ aiProfiles[0]['model-configuration'] = modelConfig;
70
+ policy['ai-security-profiles'] = aiProfiles;
71
+ await this.client.profiles.update(profile.profile_id, {
72
+ profile_name: profile.profile_name,
73
+ active: profile.active,
74
+ policy,
75
+ });
76
+ }
77
+ }
78
+ //# sourceMappingURL=management.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"management.js","sourceRoot":"","sources":["../../src/airs/management.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { ScanResult, ScanService } from './types.js';
2
+ export declare class AirsScanService implements ScanService {
3
+ private scanner;
4
+ constructor(apiKey: string);
5
+ scan(profileName: string, prompt: string, sessionId?: string): Promise<ScanResult>;
6
+ scanBatch(profileName: string, prompts: string[], concurrency?: number, sessionId?: string): Promise<ScanResult[]>;
7
+ }
8
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/airs/scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE1D,qBAAa,eAAgB,YAAW,WAAW;IACjD,OAAO,CAAC,OAAO,CAA+B;gBAElC,MAAM,EAAE,MAAM;IAKpB,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAqBlF,SAAS,CACb,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,SAAI,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC;CAMzB"}
@@ -0,0 +1,28 @@
1
+ import { Content, init, Scanner } from '@cdot65/prisma-airs-sdk';
2
+ import pLimit from 'p-limit';
3
+ export class AirsScanService {
4
+ scanner;
5
+ constructor(apiKey) {
6
+ init({ apiKey });
7
+ this.scanner = new Scanner();
8
+ }
9
+ async scan(profileName, prompt, sessionId) {
10
+ const content = new Content({ prompt });
11
+ const response = await this.scanner.syncScan({ profile_name: profileName }, content, sessionId ? { sessionId } : undefined);
12
+ const action = response.action === 'block' ? 'block' : 'allow';
13
+ const detected = response.prompt_detected;
14
+ const triggered = !!(detected?.topic_guardrails_details || detected?.topic_violation);
15
+ return {
16
+ scanId: response.scan_id ?? '',
17
+ reportId: response.report_id ?? '',
18
+ action: action,
19
+ triggered,
20
+ raw: response,
21
+ };
22
+ }
23
+ async scanBatch(profileName, prompts, concurrency = 5, sessionId) {
24
+ const limit = pLimit(concurrency);
25
+ return Promise.all(prompts.map((prompt) => limit(() => this.scan(profileName, prompt, sessionId))));
26
+ }
27
+ }
28
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/airs/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,MAAM,MAAM,SAAS,CAAC;AAG7B,MAAM,OAAO,eAAe;IAClB,OAAO,CAA+B;IAE9C,YAAY,MAAc;QACxB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,WAAmB,EAAE,MAAc,EAAE,SAAkB;QAChE,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAC1C,EAAE,YAAY,EAAE,WAAW,EAAE,EAC7B,OAAO,EACP,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CACtC,CAAC;QAEF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/D,MAAM,QAAQ,GAAG,QAAQ,CAAC,eAAsD,CAAC;QACjF,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,wBAAwB,IAAI,QAAQ,EAAE,eAAe,CAAC,CAAC;QAEtF,OAAO;YACL,MAAM,EAAE,QAAQ,CAAC,OAAO,IAAI,EAAE;YAC9B,QAAQ,EAAE,QAAQ,CAAC,SAAS,IAAI,EAAE;YAClC,MAAM,EAAE,MAA2B;YACnC,SAAS;YACT,GAAG,EAAE,QAAQ;SACd,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,SAAS,CACb,WAAmB,EACnB,OAAiB,EACjB,WAAW,GAAG,CAAC,EACf,SAAkB;QAElB,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;QAClC,OAAO,OAAO,CAAC,GAAG,CAChB,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,CAChF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * AIRS integration types — scan results and service interfaces for the
3
+ * Prisma AIRS scanner and topic management APIs.
4
+ */
5
+ import type { CreateCustomTopicRequest, CustomTopic as SdkCustomTopic } from '@cdot65/prisma-airs-sdk';
6
+ export type { CreateCustomTopicRequest, SdkCustomTopic };
7
+ export interface ScanResult {
8
+ scanId: string;
9
+ reportId: string;
10
+ action: 'allow' | 'block';
11
+ triggered: boolean;
12
+ category?: string;
13
+ raw?: unknown;
14
+ }
15
+ export interface ScanService {
16
+ scan(profileName: string, prompt: string, sessionId?: string): Promise<ScanResult>;
17
+ scanBatch(profileName: string, prompts: string[], concurrency?: number, sessionId?: string): Promise<ScanResult[]>;
18
+ }
19
+ export interface ManagementService {
20
+ createTopic(request: CreateCustomTopicRequest): Promise<SdkCustomTopic>;
21
+ updateTopic(topicId: string, request: CreateCustomTopicRequest): Promise<SdkCustomTopic>;
22
+ deleteTopic(topicId: string): Promise<void>;
23
+ listTopics(): Promise<SdkCustomTopic[]>;
24
+ assignTopicToProfile(profileName: string, topicId: string, topicName: string, action: 'allow' | 'block'): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/airs/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACV,wBAAwB,EACxB,WAAW,IAAI,cAAc,EAC9B,MAAM,yBAAyB,CAAC;AAKjC,YAAY,EAAE,wBAAwB,EAAE,cAAc,EAAE,CAAC;AAKzD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;IAC1B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAKD,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnF,SAAS,CACP,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,CAAC,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACxE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IACzF,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,UAAU,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IACxC,oBAAoB,CAClB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,OAAO,GAAG,OAAO,GACxB,OAAO,CAAC,IAAI,CAAC,CAAC;CAClB"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * AIRS integration types — scan results and service interfaces for the
3
+ * Prisma AIRS scanner and topic management APIs.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/airs/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerGenerateCommand(program: Command): void;
3
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BzC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuH9D"}
@@ -0,0 +1,127 @@
1
+ import { SdkManagementService } from '../../airs/management.js';
2
+ import { AirsScanService } from '../../airs/scanner.js';
3
+ import { loadConfig } from '../../config/loader.js';
4
+ import { runLoop } from '../../core/loop.js';
5
+ import { createLlmProvider } from '../../llm/provider.js';
6
+ import { LangChainLlmService } from '../../llm/service.js';
7
+ import { LearningExtractor } from '../../memory/extractor.js';
8
+ import { MemoryInjector } from '../../memory/injector.js';
9
+ import { MemoryStore } from '../../memory/store.js';
10
+ import { JsonFileStore } from '../../persistence/store.js';
11
+ import { collectUserInput } from '../prompts.js';
12
+ import { renderAnalysis, renderError, renderHeader, renderIterationStart, renderIterationSummary, renderLoopComplete, renderMemoryExtracted, renderMemoryLoaded, renderMetrics, renderTestProgress, renderTopic, } from '../renderer.js';
13
+ export function registerGenerateCommand(program) {
14
+ program
15
+ .command('generate')
16
+ .description('Start a new guardrail generation loop')
17
+ .option('--provider <provider>', 'LLM provider')
18
+ .option('--model <model>', 'LLM model name')
19
+ .option('--profile <name>', 'AIRS security profile name')
20
+ .option('--topic <description>', 'Topic description')
21
+ .option('--intent <intent>', 'Intent: block or allow')
22
+ .option('--max-iterations <n>', 'Max iterations', '20')
23
+ .option('--target-coverage <n>', 'Target coverage %', '90')
24
+ .option('--memory', 'Enable learning memory (default)')
25
+ .option('--no-memory', 'Disable learning memory')
26
+ .action(async (opts) => {
27
+ try {
28
+ renderHeader();
29
+ const config = await loadConfig({
30
+ llmProvider: opts.provider,
31
+ llmModel: opts.model,
32
+ memoryEnabled: opts.memory !== undefined ? String(opts.memory) : undefined,
33
+ });
34
+ // Collect user input (interactive or from CLI flags)
35
+ let userInput;
36
+ if (opts.topic && opts.profile) {
37
+ userInput = {
38
+ topicDescription: opts.topic,
39
+ intent: (opts.intent ?? 'block'),
40
+ profileName: opts.profile,
41
+ maxIterations: Number.parseInt(opts.maxIterations, 10),
42
+ targetCoverage: Number.parseInt(opts.targetCoverage, 10) / 100,
43
+ };
44
+ }
45
+ else {
46
+ userInput = await collectUserInput();
47
+ }
48
+ // Initialize services
49
+ const model = await createLlmProvider({
50
+ provider: config.llmProvider,
51
+ model: config.llmModel,
52
+ anthropicApiKey: config.anthropicApiKey,
53
+ googleApiKey: config.googleApiKey,
54
+ googleCloudProject: config.googleCloudProject,
55
+ googleCloudLocation: config.googleCloudLocation,
56
+ awsRegion: config.awsRegion,
57
+ awsAccessKeyId: config.awsAccessKeyId,
58
+ awsSecretAccessKey: config.awsSecretAccessKey,
59
+ });
60
+ // Set up memory system
61
+ const memoryEnabled = config.memoryEnabled;
62
+ const memoryStore = memoryEnabled ? new MemoryStore(config.memoryDir) : undefined;
63
+ const memoryInjector = memoryStore
64
+ ? new MemoryInjector(memoryStore, config.maxMemoryChars)
65
+ : undefined;
66
+ const llm = new LangChainLlmService(model, memoryInjector);
67
+ if (!config.airsApiKey)
68
+ throw new Error('PANW_AI_SEC_API_KEY is required');
69
+ const scanner = new AirsScanService(config.airsApiKey);
70
+ const management = new SdkManagementService({
71
+ clientId: config.mgmtClientId,
72
+ clientSecret: config.mgmtClientSecret,
73
+ tsgId: config.mgmtTsgId,
74
+ apiEndpoint: config.mgmtEndpoint,
75
+ tokenEndpoint: config.mgmtTokenEndpoint,
76
+ });
77
+ const store = new JsonFileStore(config.dataDir);
78
+ // Load memory before loop
79
+ if (memoryEnabled) {
80
+ const learningCount = await llm.loadMemory(userInput.topicDescription);
81
+ renderMemoryLoaded(learningCount);
82
+ }
83
+ const memoryExtractor = memoryStore ? new LearningExtractor(model, memoryStore) : undefined;
84
+ // Run the loop
85
+ for await (const event of runLoop(userInput, {
86
+ llm,
87
+ management,
88
+ scanner,
89
+ propagationDelayMs: config.propagationDelayMs,
90
+ memory: memoryExtractor ? { extractor: memoryExtractor } : undefined,
91
+ })) {
92
+ switch (event.type) {
93
+ case 'iteration:start':
94
+ renderIterationStart(event.iteration);
95
+ break;
96
+ case 'generate:complete':
97
+ renderTopic(event.topic);
98
+ break;
99
+ case 'test:progress':
100
+ renderTestProgress(event.completed, event.total);
101
+ break;
102
+ case 'evaluate:complete':
103
+ renderMetrics(event.metrics);
104
+ break;
105
+ case 'analyze:complete':
106
+ renderAnalysis(event.analysis);
107
+ break;
108
+ case 'iteration:complete':
109
+ renderIterationSummary(event.result);
110
+ break;
111
+ case 'memory:extracted':
112
+ renderMemoryExtracted(event.learningCount);
113
+ break;
114
+ case 'loop:complete':
115
+ await store.save(event.runState);
116
+ renderLoopComplete(event.runState);
117
+ break;
118
+ }
119
+ }
120
+ }
121
+ catch (err) {
122
+ renderError(err instanceof Error ? err.message : String(err));
123
+ process.exit(1);
124
+ }
125
+ });
126
+ }
127
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerListCommand(program: Command): void;
3
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAgB1D"}
@@ -0,0 +1,22 @@
1
+ import { loadConfig } from '../../config/loader.js';
2
+ import { JsonFileStore } from '../../persistence/store.js';
3
+ import { renderError, renderHeader, renderRunList } from '../renderer.js';
4
+ export function registerListCommand(program) {
5
+ program
6
+ .command('list')
7
+ .description('List all saved runs')
8
+ .action(async () => {
9
+ try {
10
+ renderHeader();
11
+ const config = await loadConfig();
12
+ const store = new JsonFileStore(config.dataDir);
13
+ const runs = await store.list();
14
+ renderRunList(runs);
15
+ }
16
+ catch (err) {
17
+ renderError(err instanceof Error ? err.message : String(err));
18
+ process.exit(1);
19
+ }
20
+ });
21
+ }
22
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/cli/commands/list.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE1E,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,qBAAqB,CAAC;SAClC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,IAAI,CAAC;YACH,YAAY,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAChD,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;YAChC,aAAa,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,WAAW,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerReportCommand(program: Command): void;
3
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/report.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsD5D"}
@@ -0,0 +1,57 @@
1
+ import chalk from 'chalk';
2
+ import { loadConfig } from '../../config/loader.js';
3
+ import { JsonFileStore } from '../../persistence/store.js';
4
+ import { renderAnalysis, renderError, renderHeader, renderMetrics, renderTopic, } from '../renderer.js';
5
+ export function registerReportCommand(program) {
6
+ program
7
+ .command('report <runId>')
8
+ .description('View detailed report for a run')
9
+ .option('--iteration <n>', 'Show specific iteration')
10
+ .action(async (runId, opts) => {
11
+ try {
12
+ renderHeader();
13
+ const config = await loadConfig();
14
+ const store = new JsonFileStore(config.dataDir);
15
+ const run = await store.load(runId);
16
+ if (!run) {
17
+ renderError(`Run ${runId} not found`);
18
+ process.exit(1);
19
+ }
20
+ console.log(chalk.bold(`\n Run: ${run.id}`));
21
+ console.log(` Status: ${run.status}`);
22
+ console.log(` Created: ${run.createdAt}`);
23
+ console.log(` Topic: ${run.userInput.topicDescription}`);
24
+ console.log(` Intent: ${run.userInput.intent}`);
25
+ console.log(` Best coverage: ${(run.bestCoverage * 100).toFixed(1)}% (iteration ${run.bestIteration})`);
26
+ console.log(` Total iterations: ${run.iterations.length}`);
27
+ if (opts.iteration) {
28
+ const idx = Number.parseInt(opts.iteration, 10) - 1;
29
+ const iter = run.iterations[idx];
30
+ if (!iter) {
31
+ renderError(`Iteration ${opts.iteration} not found`);
32
+ process.exit(1);
33
+ }
34
+ console.log(chalk.bold(`\n Iteration ${iter.iteration}:`));
35
+ renderTopic(iter.topic);
36
+ renderMetrics(iter.metrics);
37
+ renderAnalysis(iter.analysis);
38
+ }
39
+ else {
40
+ // Show best iteration
41
+ const best = run.iterations[run.bestIteration - 1];
42
+ if (best) {
43
+ console.log(chalk.bold(`\n Best Iteration (${best.iteration}):`));
44
+ renderTopic(best.topic);
45
+ renderMetrics(best.metrics);
46
+ renderAnalysis(best.analysis);
47
+ }
48
+ }
49
+ console.log();
50
+ }
51
+ catch (err) {
52
+ renderError(err instanceof Error ? err.message : String(err));
53
+ process.exit(1);
54
+ }
55
+ });
56
+ }
57
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/cli/commands/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerResumeCommand(program: Command): void;
3
+ //# sourceMappingURL=resume.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/resume.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2F5D"}