@loopstack/secrets-examples 0.1.1

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 (30) hide show
  1. package/README.md +148 -0
  2. package/dist/index.d.ts +4 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +20 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/secrets-examples.module.d.ts +3 -0
  7. package/dist/secrets-examples.module.d.ts.map +1 -0
  8. package/dist/secrets-examples.module.js +30 -0
  9. package/dist/secrets-examples.module.js.map +1 -0
  10. package/dist/workflows/agentic/agentic-example.ui.yaml +6 -0
  11. package/dist/workflows/agentic/agentic-example.workflow.d.ts +29 -0
  12. package/dist/workflows/agentic/agentic-example.workflow.d.ts.map +1 -0
  13. package/dist/workflows/agentic/agentic-example.workflow.js +135 -0
  14. package/dist/workflows/agentic/agentic-example.workflow.js.map +1 -0
  15. package/dist/workflows/agentic/templates/system.md +7 -0
  16. package/dist/workflows/agentic/templates/systemMessage.md +3 -0
  17. package/dist/workflows/deterministic/deterministic-example.workflow.d.ts +18 -0
  18. package/dist/workflows/deterministic/deterministic-example.workflow.d.ts.map +1 -0
  19. package/dist/workflows/deterministic/deterministic-example.workflow.js +71 -0
  20. package/dist/workflows/deterministic/deterministic-example.workflow.js.map +1 -0
  21. package/dist/workflows/deterministic/templates/secretsVerified.md +8 -0
  22. package/package.json +48 -0
  23. package/src/index.ts +3 -0
  24. package/src/secrets-examples.module.ts +17 -0
  25. package/src/workflows/agentic/agentic-example.ui.yaml +6 -0
  26. package/src/workflows/agentic/agentic-example.workflow.ts +100 -0
  27. package/src/workflows/agentic/templates/system.md +7 -0
  28. package/src/workflows/agentic/templates/systemMessage.md +3 -0
  29. package/src/workflows/deterministic/deterministic-example.workflow.ts +47 -0
  30. package/src/workflows/deterministic/templates/secretsVerified.md +8 -0
package/README.md ADDED
@@ -0,0 +1,148 @@
1
+ ---
2
+ title: Secrets Examples
3
+ description: Workflow examples for secrets management in Loopstack — deterministic request/verify flow and an agentic LLM flow using get_secret_keys and request_secrets_task tools
4
+ ---
5
+
6
+ # @loopstack/secrets-examples
7
+
8
+ > Secrets workflow examples for the [Loopstack](https://loopstack.ai) automation framework.
9
+
10
+ Two ways to manage workspace secrets: a scripted request/verify flow, and an agent loop where the LLM decides when to ask the user for credentials.
11
+
12
+ ## Install as Source (Recommended)
13
+
14
+ Examples are meant to be read, copied, and adapted. Pull the source straight into your project with [giget](https://github.com/unjs/giget):
15
+
16
+ ```bash
17
+ npx giget@latest gh:loopstack-ai/loopstack/registry/examples/secrets-examples src/secrets-examples
18
+ ```
19
+
20
+ After copying, register the module in your app:
21
+
22
+ ```typescript
23
+ import { Module } from '@nestjs/common';
24
+ import { LoopstackModule } from '@loopstack/loopstack-module';
25
+ import { SecretsExamplesModule } from './secrets-examples/secrets-examples.module';
26
+
27
+ @Module({
28
+ imports: [LoopstackModule.forRoot(), SecretsExamplesModule],
29
+ })
30
+ export class AppModule {}
31
+ ```
32
+
33
+ ## Install as a Dependency
34
+
35
+ ```bash
36
+ npm install @loopstack/secrets-examples
37
+ ```
38
+
39
+ ```typescript
40
+ import { SecretsExamplesModule } from '@loopstack/secrets-examples';
41
+ ```
42
+
43
+ ## Environment
44
+
45
+ The agentic example requires Claude credentials:
46
+
47
+ ```bash
48
+ ANTHROPIC_API_KEY=sk-ant-...
49
+ ```
50
+
51
+ ## Examples
52
+
53
+ | Example | Studio title | Description |
54
+ | ------------------------------- | --------------------------------- | -------------------------------------------------------------------- |
55
+ | [Deterministic](#deterministic) | `Secrets - Deterministic Example` | Scripted request/verify flow — no LLM involved |
56
+ | [Agentic](#agentic) | `Secrets - Agentic Example` | LLM agent that checks, requests, and verifies secrets via tool calls |
57
+
58
+ ---
59
+
60
+ ## Deterministic
61
+
62
+ A scripted workflow that requests two secrets from the user, waits for them to be stored, then verifies they were saved. No LLM involved.
63
+
64
+ ### What it demonstrates
65
+
66
+ - Calling `RequestSecretsTool` with a list of expected keys
67
+ - Persisting a `SecretRequestDocument` so the user sees the prompt in Studio
68
+ - A `wait: true` transition that resumes once the user submits the secrets
69
+ - Reading current key availability via `GetSecretKeysTool`
70
+
71
+ ### Key code
72
+
73
+ ```ts
74
+ @Transition({ to: 'requesting_secrets' })
75
+ async requestSecretsFromUser() {
76
+ await this.requestSecrets.call({
77
+ variables: [{ key: 'EXAMPLE_API_KEY' }, { key: 'EXAMPLE_SECRET' }],
78
+ });
79
+ await this.documentStore.save(SecretRequestDocument, {
80
+ variables: [{ key: 'EXAMPLE_API_KEY' }, { key: 'EXAMPLE_SECRET' }],
81
+ });
82
+ }
83
+
84
+ @Transition({ from: 'requesting_secrets', to: 'verifying', wait: true })
85
+ async secretsSubmitted() {
86
+ const result = await this.getSecretKeys.call();
87
+ this.assignState({ secretKeys: result.data });
88
+ }
89
+ ```
90
+
91
+ ### Files
92
+
93
+ - `deterministic-example.workflow.ts` — workflow class
94
+ - `templates/secretsVerified.md` — Handlebars summary template
95
+
96
+ ## Agentic
97
+
98
+ An agent workflow where the LLM decides when to check for existing secrets and when to request new ones. The user can also send follow-up messages mid-loop.
99
+
100
+ ### What it demonstrates
101
+
102
+ - Configuring an LLM call with allowed tools via `config: { tools: ['get_secret_keys', 'request_secrets_task'] }`
103
+ - A delegate/tool-result loop using `LlmDelegateToolCallsTool` + `LlmUpdateToolResultTool`
104
+ - Guard-based routing on `stopReason === 'tool_use'` vs end-of-turn
105
+ - A `prompt-input` widget that lets the user inject messages while the agent runs
106
+
107
+ ### Key code
108
+
109
+ ```ts
110
+ @Transition({ from: 'ready', to: 'prompt_executed' })
111
+ async llmTurn() {
112
+ const result = await this.llmGenerateText.call(
113
+ {},
114
+ {
115
+ config: {
116
+ provider: 'claude',
117
+ model: 'claude-haiku-4-5-20251001',
118
+ tools: ['get_secret_keys', 'request_secrets_task'],
119
+ system: this.render(join(__dirname, 'templates', 'system.md')),
120
+ },
121
+ },
122
+ );
123
+ this.assignState({ llmResult: result.data });
124
+ }
125
+
126
+ @Transition({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 })
127
+ @Guard('hasToolCalls')
128
+ async executeToolCalls(state) {
129
+ const result = await this.llmDelegateToolCalls.call({
130
+ message: state.llmResult!.message,
131
+ callback: { transition: 'toolResultReceived' },
132
+ });
133
+ this.assignState({ delegateResult: result.data });
134
+ }
135
+ ```
136
+
137
+ ### Files
138
+
139
+ - `agentic-example.workflow.ts` — workflow class
140
+ - `agentic-example.ui.yaml` — `prompt-input` widget for follow-up messages
141
+ - `templates/system.md` — system prompt
142
+ - `templates/systemMessage.md` — initial user/context message
143
+
144
+ ## About
145
+
146
+ Author: [Jakob Klippel](https://www.linkedin.com/in/jakob-klippel/)
147
+
148
+ License: MIT
@@ -0,0 +1,4 @@
1
+ export * from './secrets-examples.module';
2
+ export * from './workflows/deterministic/deterministic-example.workflow';
3
+ export * from './workflows/agentic/agentic-example.workflow';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0DAA0D,CAAC;AACzE,cAAc,8CAA8C,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./secrets-examples.module"), exports);
18
+ __exportStar(require("./workflows/deterministic/deterministic-example.workflow"), exports);
19
+ __exportStar(require("./workflows/agentic/agentic-example.workflow"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4DAA0C;AAC1C,2FAAyE;AACzE,+EAA6D"}
@@ -0,0 +1,3 @@
1
+ export declare class SecretsExamplesModule {
2
+ }
3
+ //# sourceMappingURL=secrets-examples.module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets-examples.module.d.ts","sourceRoot":"","sources":["../src/secrets-examples.module.ts"],"names":[],"mappings":"AAOA,qBASa,qBAAqB;CAAG"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.SecretsExamplesModule = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const claude_module_1 = require("@loopstack/claude-module");
12
+ const common_2 = require("@loopstack/common");
13
+ const secrets_module_1 = require("@loopstack/secrets-module");
14
+ const agentic_example_workflow_1 = require("./workflows/agentic/agentic-example.workflow");
15
+ const deterministic_example_workflow_1 = require("./workflows/deterministic/deterministic-example.workflow");
16
+ let SecretsExamplesModule = class SecretsExamplesModule {
17
+ };
18
+ exports.SecretsExamplesModule = SecretsExamplesModule;
19
+ exports.SecretsExamplesModule = SecretsExamplesModule = __decorate([
20
+ (0, common_2.StudioApp)({
21
+ title: 'Secrets Examples',
22
+ workflows: [deterministic_example_workflow_1.DeterministicExampleWorkflow, agentic_example_workflow_1.AgenticExampleWorkflow],
23
+ }),
24
+ (0, common_1.Module)({
25
+ imports: [claude_module_1.ClaudeModule, secrets_module_1.SecretsModule.forFeature()],
26
+ providers: [deterministic_example_workflow_1.DeterministicExampleWorkflow, agentic_example_workflow_1.AgenticExampleWorkflow],
27
+ exports: [deterministic_example_workflow_1.DeterministicExampleWorkflow, agentic_example_workflow_1.AgenticExampleWorkflow],
28
+ })
29
+ ], SecretsExamplesModule);
30
+ //# sourceMappingURL=secrets-examples.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secrets-examples.module.js","sourceRoot":"","sources":["../src/secrets-examples.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,4DAAwD;AACxD,8CAA8C;AAC9C,8DAA0D;AAC1D,2FAAsF;AACtF,6GAAwG;AAWjG,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;CAAG,CAAA;AAAxB,sDAAqB;gCAArB,qBAAqB;IATjC,IAAA,kBAAS,EAAC;QACT,KAAK,EAAE,kBAAkB;QACzB,SAAS,EAAE,CAAC,6DAA4B,EAAE,iDAAsB,CAAC;KAClE,CAAC;IACD,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,4BAAY,EAAE,8BAAa,CAAC,UAAU,EAAE,CAAC;QACnD,SAAS,EAAE,CAAC,6DAA4B,EAAE,iDAAsB,CAAC;QACjE,OAAO,EAAE,CAAC,6DAA4B,EAAE,iDAAsB,CAAC;KAChE,CAAC;GACW,qBAAqB,CAAG"}
@@ -0,0 +1,6 @@
1
+ widget: prompt-input
2
+ enabledWhen:
3
+ - waiting_for_user
4
+ options:
5
+ transition: userMessage
6
+ label: Send Message
@@ -0,0 +1,29 @@
1
+ import { BaseWorkflow } from '@loopstack/common';
2
+ import type { TransitionInput } from '@loopstack/common';
3
+ import type { LlmDelegateResult, LlmGenerateTextResult } from '@loopstack/llm-provider-module';
4
+ import { LlmDelegateToolCallsTool, LlmGenerateTextTool, LlmUpdateToolResultTool } from '@loopstack/llm-provider-module';
5
+ import { GetSecretKeysTool, RequestSecretsTask, SecretsRequestWorkflow } from '@loopstack/secrets-module';
6
+ interface AgenticState {
7
+ llmResult?: LlmGenerateTextResult;
8
+ delegateResult?: LlmDelegateResult;
9
+ }
10
+ export declare class AgenticExampleWorkflow extends BaseWorkflow {
11
+ private readonly llmGenerateText;
12
+ private readonly llmDelegateToolCalls;
13
+ private readonly llmUpdateToolResult;
14
+ private readonly requestSecrets;
15
+ private readonly getSecretKeys;
16
+ private readonly secretsRequest;
17
+ constructor(llmGenerateText: LlmGenerateTextTool, llmDelegateToolCalls: LlmDelegateToolCallsTool, llmUpdateToolResult: LlmUpdateToolResultTool, requestSecrets: RequestSecretsTask, getSecretKeys: GetSecretKeysTool, secretsRequest: SecretsRequestWorkflow);
18
+ setup(_state: AgenticState): Promise<void>;
19
+ llmTurn(_state: AgenticState): Promise<void>;
20
+ executeToolCalls(state: AgenticState): Promise<void>;
21
+ hasToolCalls(state: AgenticState): boolean;
22
+ toolResultReceived(state: AgenticState, input: TransitionInput<Record<string, unknown>>): Promise<void>;
23
+ allToolsCompleteTransition(_state: AgenticState): void;
24
+ allToolsComplete(state: AgenticState): boolean;
25
+ userMessage(state: AgenticState, input: TransitionInput<string>): Promise<void>;
26
+ respond(_state: AgenticState): void;
27
+ }
28
+ export {};
29
+ //# sourceMappingURL=agentic-example.workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentic-example.workflow.d.ts","sourceRoot":"","sources":["../../../src/workflows/agentic/agentic-example.workflow.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAA+B,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC/F,OAAO,EAEL,wBAAwB,EACxB,mBAAmB,EAEnB,uBAAuB,EACxB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAE1G,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,cAAc,CAAC,EAAE,iBAAiB,CAAC;CACpC;AAED,qBAMa,sBAAuB,SAAQ,YAAY;IAEpD,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,oBAAoB;IACrC,OAAO,CAAC,QAAQ,CAAC,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,cAAc;gBALd,eAAe,EAAE,mBAAmB,EACpC,oBAAoB,EAAE,wBAAwB,EAC9C,mBAAmB,EAAE,uBAAuB,EAC5C,cAAc,EAAE,kBAAkB,EAClC,aAAa,EAAE,iBAAiB,EAChC,cAAc,EAAE,sBAAsB;IAMnD,KAAK,CAAC,MAAM,EAAE,YAAY;IAQ1B,OAAO,CAAC,MAAM,EAAE,YAAY;IAiB5B,gBAAgB,CAAC,KAAK,EAAE,YAAY;IAQ1C,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO;IAKpC,kBAAkB,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAU7F,0BAA0B,CAAC,MAAM,EAAE,YAAY;IAE/C,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO;IAKxC,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,eAAe,CAAC,MAAM,CAAC;IAKrE,OAAO,CAAC,MAAM,EAAE,YAAY;CAC7B"}
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AgenticExampleWorkflow = void 0;
13
+ const node_path_1 = require("node:path");
14
+ const zod_1 = require("zod");
15
+ const common_1 = require("@loopstack/common");
16
+ const llm_provider_module_1 = require("@loopstack/llm-provider-module");
17
+ const secrets_module_1 = require("@loopstack/secrets-module");
18
+ let AgenticExampleWorkflow = class AgenticExampleWorkflow extends common_1.BaseWorkflow {
19
+ llmGenerateText;
20
+ llmDelegateToolCalls;
21
+ llmUpdateToolResult;
22
+ requestSecrets;
23
+ getSecretKeys;
24
+ secretsRequest;
25
+ constructor(llmGenerateText, llmDelegateToolCalls, llmUpdateToolResult, requestSecrets, getSecretKeys, secretsRequest) {
26
+ super();
27
+ this.llmGenerateText = llmGenerateText;
28
+ this.llmDelegateToolCalls = llmDelegateToolCalls;
29
+ this.llmUpdateToolResult = llmUpdateToolResult;
30
+ this.requestSecrets = requestSecrets;
31
+ this.getSecretKeys = getSecretKeys;
32
+ this.secretsRequest = secretsRequest;
33
+ }
34
+ async setup(_state) {
35
+ await this.documentStore.save(llm_provider_module_1.LlmContextDocument, {
36
+ role: 'user',
37
+ text: this.render((0, node_path_1.join)(__dirname, 'templates', 'systemMessage.md')),
38
+ });
39
+ }
40
+ async llmTurn(_state) {
41
+ const result = await this.llmGenerateText.call({}, {
42
+ config: {
43
+ provider: 'claude',
44
+ model: 'claude-haiku-4-5-20251001',
45
+ tools: ['get_secret_keys', 'request_secrets_task'],
46
+ system: this.render((0, node_path_1.join)(__dirname, 'templates', 'system.md')),
47
+ },
48
+ });
49
+ this.assignState({ llmResult: result.data });
50
+ }
51
+ async executeToolCalls(state) {
52
+ const result = await this.llmDelegateToolCalls.call({
53
+ message: state.llmResult.message,
54
+ callback: { transition: 'toolResultReceived' },
55
+ });
56
+ this.assignState({ delegateResult: result.data });
57
+ }
58
+ hasToolCalls(state) {
59
+ return state.llmResult?.message.stopReason === 'tool_use';
60
+ }
61
+ async toolResultReceived(state, input) {
62
+ const result = await this.llmUpdateToolResult.call({
63
+ delegateResult: state.delegateResult,
64
+ completedTool: input,
65
+ });
66
+ this.assignState({ delegateResult: result.data });
67
+ }
68
+ allToolsCompleteTransition(_state) { }
69
+ allToolsComplete(state) {
70
+ return state.delegateResult?.allCompleted ?? false;
71
+ }
72
+ async userMessage(state, input) {
73
+ await this.documentStore.save(llm_provider_module_1.LlmMessageDocument, { role: 'user', text: input.data });
74
+ }
75
+ respond(_state) { }
76
+ };
77
+ exports.AgenticExampleWorkflow = AgenticExampleWorkflow;
78
+ __decorate([
79
+ (0, common_1.Transition)({ to: 'ready' }),
80
+ __metadata("design:type", Function),
81
+ __metadata("design:paramtypes", [Object]),
82
+ __metadata("design:returntype", Promise)
83
+ ], AgenticExampleWorkflow.prototype, "setup", null);
84
+ __decorate([
85
+ (0, common_1.Transition)({ from: 'ready', to: 'prompt_executed' }),
86
+ __metadata("design:type", Function),
87
+ __metadata("design:paramtypes", [Object]),
88
+ __metadata("design:returntype", Promise)
89
+ ], AgenticExampleWorkflow.prototype, "llmTurn", null);
90
+ __decorate([
91
+ (0, common_1.Transition)({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 }),
92
+ (0, common_1.Guard)('hasToolCalls'),
93
+ __metadata("design:type", Function),
94
+ __metadata("design:paramtypes", [Object]),
95
+ __metadata("design:returntype", Promise)
96
+ ], AgenticExampleWorkflow.prototype, "executeToolCalls", null);
97
+ __decorate([
98
+ (0, common_1.Transition)({ from: 'awaiting_tools', to: 'awaiting_tools', wait: true, schema: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()) }),
99
+ __metadata("design:type", Function),
100
+ __metadata("design:paramtypes", [Object, Object]),
101
+ __metadata("design:returntype", Promise)
102
+ ], AgenticExampleWorkflow.prototype, "toolResultReceived", null);
103
+ __decorate([
104
+ (0, common_1.Transition)({ from: 'awaiting_tools', to: 'ready' }),
105
+ (0, common_1.Guard)('allToolsComplete'),
106
+ __metadata("design:type", Function),
107
+ __metadata("design:paramtypes", [Object]),
108
+ __metadata("design:returntype", void 0)
109
+ ], AgenticExampleWorkflow.prototype, "allToolsCompleteTransition", null);
110
+ __decorate([
111
+ (0, common_1.Transition)({ from: 'waiting_for_user', to: 'ready', wait: true, schema: zod_1.z.string() }),
112
+ __metadata("design:type", Function),
113
+ __metadata("design:paramtypes", [Object, Object]),
114
+ __metadata("design:returntype", Promise)
115
+ ], AgenticExampleWorkflow.prototype, "userMessage", null);
116
+ __decorate([
117
+ (0, common_1.Transition)({ from: 'prompt_executed', to: 'end' }),
118
+ __metadata("design:type", Function),
119
+ __metadata("design:paramtypes", [Object]),
120
+ __metadata("design:returntype", void 0)
121
+ ], AgenticExampleWorkflow.prototype, "respond", null);
122
+ exports.AgenticExampleWorkflow = AgenticExampleWorkflow = __decorate([
123
+ (0, common_1.Workflow)({
124
+ title: 'Secrets - Agentic Example',
125
+ description: 'An agent workflow where the LLM autonomously manages secrets by calling getSecretKeys and requestSecrets tools. The user can send follow-up messages.',
126
+ widget: './agentic-example.ui.yaml',
127
+ }),
128
+ __metadata("design:paramtypes", [llm_provider_module_1.LlmGenerateTextTool,
129
+ llm_provider_module_1.LlmDelegateToolCallsTool,
130
+ llm_provider_module_1.LlmUpdateToolResultTool,
131
+ secrets_module_1.RequestSecretsTask,
132
+ secrets_module_1.GetSecretKeysTool,
133
+ secrets_module_1.SecretsRequestWorkflow])
134
+ ], AgenticExampleWorkflow);
135
+ //# sourceMappingURL=agentic-example.workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentic-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/agentic/agentic-example.workflow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ You are a helpful assistant that manages workspace secrets.
2
+ Use getSecretKeys to check existing secrets, and requestSecrets to ask the user for new ones.
3
+
4
+ IMPORTANT: When using requestSecrets, it must be the ONLY tool call in your response.
5
+ Do not combine it with other tool calls.
6
+
7
+ When all secrets are available, respond with one sentence including a list of the requested secrets.
@@ -0,0 +1,3 @@
1
+ Check what secrets are available in the workspace using getSecretKeys.
2
+ If EXAMPLE_API_KEY and EXAMPLE_SECRET are not yet stored, request them from the user.
3
+ After secrets are stored, verify by listing them again and summarize.
@@ -0,0 +1,18 @@
1
+ import { BaseWorkflow } from '@loopstack/common';
2
+ import { GetSecretKeysTool, RequestSecretsTool } from '@loopstack/secrets-module';
3
+ interface DeterministicState {
4
+ secretKeys?: Array<{
5
+ key: string;
6
+ hasValue: boolean;
7
+ }>;
8
+ }
9
+ export declare class DeterministicExampleWorkflow extends BaseWorkflow {
10
+ private readonly requestSecrets;
11
+ private readonly getSecretKeys;
12
+ constructor(requestSecrets: RequestSecretsTool, getSecretKeys: GetSecretKeysTool);
13
+ requestSecretsFromUser(_state: DeterministicState): Promise<void>;
14
+ secretsSubmitted(_state: DeterministicState): Promise<void>;
15
+ showResult(state: DeterministicState): Promise<void>;
16
+ }
17
+ export {};
18
+ //# sourceMappingURL=deterministic-example.workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic-example.workflow.d.ts","sourceRoot":"","sources":["../../../src/workflows/deterministic/deterministic-example.workflow.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAA0C,MAAM,mBAAmB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAyB,MAAM,2BAA2B,CAAC;AAEzG,UAAU,kBAAkB;IAC1B,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACxD;AAED,qBAKa,4BAA6B,SAAQ,YAAY;IAE1D,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,aAAa;gBADb,cAAc,EAAE,kBAAkB,EAClC,aAAa,EAAE,iBAAiB;IAM7C,sBAAsB,CAAC,MAAM,EAAE,kBAAkB;IAWjD,gBAAgB,CAAC,MAAM,EAAE,kBAAkB;IAM3C,UAAU,CAAC,KAAK,EAAE,kBAAkB;CAO3C"}
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.DeterministicExampleWorkflow = void 0;
13
+ const node_path_1 = require("node:path");
14
+ const common_1 = require("@loopstack/common");
15
+ const secrets_module_1 = require("@loopstack/secrets-module");
16
+ let DeterministicExampleWorkflow = class DeterministicExampleWorkflow extends common_1.BaseWorkflow {
17
+ requestSecrets;
18
+ getSecretKeys;
19
+ constructor(requestSecrets, getSecretKeys) {
20
+ super();
21
+ this.requestSecrets = requestSecrets;
22
+ this.getSecretKeys = getSecretKeys;
23
+ }
24
+ async requestSecretsFromUser(_state) {
25
+ await this.requestSecrets.call({
26
+ variables: [{ key: 'EXAMPLE_API_KEY' }, { key: 'EXAMPLE_SECRET' }],
27
+ });
28
+ await this.documentStore.save(secrets_module_1.SecretRequestDocument, {
29
+ variables: [{ key: 'EXAMPLE_API_KEY' }, { key: 'EXAMPLE_SECRET' }],
30
+ });
31
+ }
32
+ async secretsSubmitted(_state) {
33
+ const result = await this.getSecretKeys.call();
34
+ this.assignState({ secretKeys: result.data });
35
+ }
36
+ async showResult(state) {
37
+ await this.documentStore.save(common_1.MarkdownDocument, {
38
+ markdown: this.render((0, node_path_1.join)(__dirname, 'templates', 'secretsVerified.md'), {
39
+ secretKeys: state.secretKeys,
40
+ }),
41
+ });
42
+ }
43
+ };
44
+ exports.DeterministicExampleWorkflow = DeterministicExampleWorkflow;
45
+ __decorate([
46
+ (0, common_1.Transition)({ to: 'requesting_secrets' }),
47
+ __metadata("design:type", Function),
48
+ __metadata("design:paramtypes", [Object]),
49
+ __metadata("design:returntype", Promise)
50
+ ], DeterministicExampleWorkflow.prototype, "requestSecretsFromUser", null);
51
+ __decorate([
52
+ (0, common_1.Transition)({ from: 'requesting_secrets', to: 'verifying', wait: true }),
53
+ __metadata("design:type", Function),
54
+ __metadata("design:paramtypes", [Object]),
55
+ __metadata("design:returntype", Promise)
56
+ ], DeterministicExampleWorkflow.prototype, "secretsSubmitted", null);
57
+ __decorate([
58
+ (0, common_1.Transition)({ from: 'verifying', to: 'end' }),
59
+ __metadata("design:type", Function),
60
+ __metadata("design:paramtypes", [Object]),
61
+ __metadata("design:returntype", Promise)
62
+ ], DeterministicExampleWorkflow.prototype, "showResult", null);
63
+ exports.DeterministicExampleWorkflow = DeterministicExampleWorkflow = __decorate([
64
+ (0, common_1.Workflow)({
65
+ title: 'Secrets - Deterministic Example',
66
+ description: 'A scripted workflow that requests two secrets from the user, waits for them to be stored, then verifies the result. No LLM involved.',
67
+ }),
68
+ __metadata("design:paramtypes", [secrets_module_1.RequestSecretsTool,
69
+ secrets_module_1.GetSecretKeysTool])
70
+ ], DeterministicExampleWorkflow);
71
+ //# sourceMappingURL=deterministic-example.workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/deterministic/deterministic-example.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,yCAAiC;AACjC,8CAAyF;AACzF,8DAAyG;AAWlG,IAAM,4BAA4B,GAAlC,MAAM,4BAA6B,SAAQ,qBAAY;IAEzC;IACA;IAFnB,YACmB,cAAkC,EAClC,aAAgC;QAEjD,KAAK,EAAE,CAAC;QAHS,mBAAc,GAAd,cAAc,CAAoB;QAClC,kBAAa,GAAb,aAAa,CAAmB;IAGnD,CAAC;IAGK,AAAN,KAAK,CAAC,sBAAsB,CAAC,MAA0B;QACrD,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC;YAC7B,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,iBAAiB,EAAE,EAAE,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC;SACnE,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,sCAAqB,EAAE;YACnD,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,iBAAiB,EAAE,EAAE,EAAE,GAAG,EAAE,gBAAgB,EAAE,CAAC;SACnE,CAAC,CAAC;IACL,CAAC;IAGK,AAAN,KAAK,CAAC,gBAAgB,CAAC,MAA0B;QAC/C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;QAC/C,IAAI,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAGK,AAAN,KAAK,CAAC,UAAU,CAAC,KAAyB;QACxC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,yBAAgB,EAAE;YAC9C,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,IAAA,gBAAI,EAAC,SAAS,EAAE,WAAW,EAAE,oBAAoB,CAAC,EAAE;gBACxE,UAAU,EAAE,KAAK,CAAC,UAAU;aAC7B,CAAC;SACH,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAjCY,oEAA4B;AASjC;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,oBAAoB,EAAE,CAAC;;;;0EASxC;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;;;;oEAIvE;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;;;;8DAO5C;uCAhCU,4BAA4B;IALxC,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,iCAAiC;QACxC,WAAW,EACT,sIAAsI;KACzI,CAAC;qCAGmC,mCAAkB;QACnB,kCAAiB;GAHxC,4BAA4B,CAiCxC"}
@@ -0,0 +1,8 @@
1
+ # Secrets Verified
2
+
3
+ The following secrets are now stored:
4
+
5
+ {{#each secretKeys}}
6
+
7
+ - **{{this.key}}**: {{#if this.hasValue}}has value{{else}}no value{{/if}}
8
+ {{/each}}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@loopstack/secrets-examples",
3
+ "displayName": "Loopstack Secrets Examples",
4
+ "description": "Workflow examples for secrets management in Loopstack — deterministic request/verify flow and an agentic LLM flow that calls secrets tools.",
5
+ "keywords": [
6
+ "loopstack",
7
+ "example",
8
+ "secrets",
9
+ "workflow"
10
+ ],
11
+ "version": "0.1.1",
12
+ "license": "MIT",
13
+ "author": {
14
+ "name": "Jakob Klippel",
15
+ "url": "https://www.linkedin.com/in/jakob-klippel/"
16
+ },
17
+ "main": "dist/index.js",
18
+ "types": "dist/index.d.ts",
19
+ "exports": {
20
+ ".": "./dist/index.js",
21
+ "./src/*": "./src/*"
22
+ },
23
+ "scripts": {
24
+ "build": "nest build",
25
+ "compile": "tsc --noEmit",
26
+ "format": "prettier --write .",
27
+ "lint": "eslint .",
28
+ "test": "vitest run --passWithNoTests",
29
+ "watch": "nest build --watch"
30
+ },
31
+ "dependencies": {
32
+ "@loopstack/claude-module": "*",
33
+ "@loopstack/common": "*",
34
+ "@loopstack/llm-provider-module": "*",
35
+ "@loopstack/secrets-module": "*",
36
+ "@nestjs/common": "^11.1.19",
37
+ "zod": "^4.3.6"
38
+ },
39
+ "files": [
40
+ "dist",
41
+ "src"
42
+ ],
43
+ "devDependencies": {
44
+ "vitest": "^4.1.6",
45
+ "@swc/core": "^1.15.33",
46
+ "unplugin-swc": "^1.5.9"
47
+ }
48
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from './secrets-examples.module';
2
+ export * from './workflows/deterministic/deterministic-example.workflow';
3
+ export * from './workflows/agentic/agentic-example.workflow';
@@ -0,0 +1,17 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { ClaudeModule } from '@loopstack/claude-module';
3
+ import { StudioApp } from '@loopstack/common';
4
+ import { SecretsModule } from '@loopstack/secrets-module';
5
+ import { AgenticExampleWorkflow } from './workflows/agentic/agentic-example.workflow';
6
+ import { DeterministicExampleWorkflow } from './workflows/deterministic/deterministic-example.workflow';
7
+
8
+ @StudioApp({
9
+ title: 'Secrets Examples',
10
+ workflows: [DeterministicExampleWorkflow, AgenticExampleWorkflow],
11
+ })
12
+ @Module({
13
+ imports: [ClaudeModule, SecretsModule.forFeature()],
14
+ providers: [DeterministicExampleWorkflow, AgenticExampleWorkflow],
15
+ exports: [DeterministicExampleWorkflow, AgenticExampleWorkflow],
16
+ })
17
+ export class SecretsExamplesModule {}
@@ -0,0 +1,6 @@
1
+ widget: prompt-input
2
+ enabledWhen:
3
+ - waiting_for_user
4
+ options:
5
+ transition: userMessage
6
+ label: Send Message
@@ -0,0 +1,100 @@
1
+ import { join } from 'node:path';
2
+ import { z } from 'zod';
3
+ import { BaseWorkflow, Guard, Transition, Workflow } from '@loopstack/common';
4
+ import type { TransitionInput } from '@loopstack/common';
5
+ import type { LlmDelegateResult, LlmGenerateTextResult } from '@loopstack/llm-provider-module';
6
+ import {
7
+ LlmContextDocument,
8
+ LlmDelegateToolCallsTool,
9
+ LlmGenerateTextTool,
10
+ LlmMessageDocument,
11
+ LlmUpdateToolResultTool,
12
+ } from '@loopstack/llm-provider-module';
13
+ import { GetSecretKeysTool, RequestSecretsTask, SecretsRequestWorkflow } from '@loopstack/secrets-module';
14
+
15
+ interface AgenticState {
16
+ llmResult?: LlmGenerateTextResult;
17
+ delegateResult?: LlmDelegateResult;
18
+ }
19
+
20
+ @Workflow({
21
+ title: 'Secrets - Agentic Example',
22
+ description:
23
+ 'An agent workflow where the LLM autonomously manages secrets by calling getSecretKeys and requestSecrets tools. The user can send follow-up messages.',
24
+ widget: './agentic-example.ui.yaml',
25
+ })
26
+ export class AgenticExampleWorkflow extends BaseWorkflow {
27
+ constructor(
28
+ private readonly llmGenerateText: LlmGenerateTextTool,
29
+ private readonly llmDelegateToolCalls: LlmDelegateToolCallsTool,
30
+ private readonly llmUpdateToolResult: LlmUpdateToolResultTool,
31
+ private readonly requestSecrets: RequestSecretsTask,
32
+ private readonly getSecretKeys: GetSecretKeysTool,
33
+ private readonly secretsRequest: SecretsRequestWorkflow,
34
+ ) {
35
+ super();
36
+ }
37
+
38
+ @Transition({ to: 'ready' })
39
+ async setup(_state: AgenticState) {
40
+ await this.documentStore.save(LlmContextDocument, {
41
+ role: 'user',
42
+ text: this.render(join(__dirname, 'templates', 'systemMessage.md')),
43
+ });
44
+ }
45
+
46
+ @Transition({ from: 'ready', to: 'prompt_executed' })
47
+ async llmTurn(_state: AgenticState) {
48
+ const result = await this.llmGenerateText.call(
49
+ {},
50
+ {
51
+ config: {
52
+ provider: 'claude',
53
+ model: 'claude-haiku-4-5-20251001',
54
+ tools: ['get_secret_keys', 'request_secrets_task'],
55
+ system: this.render(join(__dirname, 'templates', 'system.md')),
56
+ },
57
+ },
58
+ );
59
+ this.assignState({ llmResult: result.data });
60
+ }
61
+
62
+ @Transition({ from: 'prompt_executed', to: 'awaiting_tools', priority: 10 })
63
+ @Guard('hasToolCalls')
64
+ async executeToolCalls(state: AgenticState) {
65
+ const result = await this.llmDelegateToolCalls.call({
66
+ message: state.llmResult!.message,
67
+ callback: { transition: 'toolResultReceived' },
68
+ });
69
+ this.assignState({ delegateResult: result.data });
70
+ }
71
+
72
+ hasToolCalls(state: AgenticState): boolean {
73
+ return state.llmResult?.message.stopReason === 'tool_use';
74
+ }
75
+
76
+ @Transition({ from: 'awaiting_tools', to: 'awaiting_tools', wait: true, schema: z.record(z.string(), z.unknown()) })
77
+ async toolResultReceived(state: AgenticState, input: TransitionInput<Record<string, unknown>>) {
78
+ const result = await this.llmUpdateToolResult.call({
79
+ delegateResult: state.delegateResult!,
80
+ completedTool: input,
81
+ });
82
+ this.assignState({ delegateResult: result.data });
83
+ }
84
+
85
+ @Transition({ from: 'awaiting_tools', to: 'ready' })
86
+ @Guard('allToolsComplete')
87
+ allToolsCompleteTransition(_state: AgenticState) {}
88
+
89
+ allToolsComplete(state: AgenticState): boolean {
90
+ return state.delegateResult?.allCompleted ?? false;
91
+ }
92
+
93
+ @Transition({ from: 'waiting_for_user', to: 'ready', wait: true, schema: z.string() })
94
+ async userMessage(state: AgenticState, input: TransitionInput<string>) {
95
+ await this.documentStore.save(LlmMessageDocument, { role: 'user', text: input.data });
96
+ }
97
+
98
+ @Transition({ from: 'prompt_executed', to: 'end' })
99
+ respond(_state: AgenticState) {}
100
+ }
@@ -0,0 +1,7 @@
1
+ You are a helpful assistant that manages workspace secrets.
2
+ Use getSecretKeys to check existing secrets, and requestSecrets to ask the user for new ones.
3
+
4
+ IMPORTANT: When using requestSecrets, it must be the ONLY tool call in your response.
5
+ Do not combine it with other tool calls.
6
+
7
+ When all secrets are available, respond with one sentence including a list of the requested secrets.
@@ -0,0 +1,3 @@
1
+ Check what secrets are available in the workspace using getSecretKeys.
2
+ If EXAMPLE_API_KEY and EXAMPLE_SECRET are not yet stored, request them from the user.
3
+ After secrets are stored, verify by listing them again and summarize.
@@ -0,0 +1,47 @@
1
+ import { join } from 'node:path';
2
+ import { BaseWorkflow, MarkdownDocument, Transition, Workflow } from '@loopstack/common';
3
+ import { GetSecretKeysTool, RequestSecretsTool, SecretRequestDocument } from '@loopstack/secrets-module';
4
+
5
+ interface DeterministicState {
6
+ secretKeys?: Array<{ key: string; hasValue: boolean }>;
7
+ }
8
+
9
+ @Workflow({
10
+ title: 'Secrets - Deterministic Example',
11
+ description:
12
+ 'A scripted workflow that requests two secrets from the user, waits for them to be stored, then verifies the result. No LLM involved.',
13
+ })
14
+ export class DeterministicExampleWorkflow extends BaseWorkflow {
15
+ constructor(
16
+ private readonly requestSecrets: RequestSecretsTool,
17
+ private readonly getSecretKeys: GetSecretKeysTool,
18
+ ) {
19
+ super();
20
+ }
21
+
22
+ @Transition({ to: 'requesting_secrets' })
23
+ async requestSecretsFromUser(_state: DeterministicState) {
24
+ await this.requestSecrets.call({
25
+ variables: [{ key: 'EXAMPLE_API_KEY' }, { key: 'EXAMPLE_SECRET' }],
26
+ });
27
+
28
+ await this.documentStore.save(SecretRequestDocument, {
29
+ variables: [{ key: 'EXAMPLE_API_KEY' }, { key: 'EXAMPLE_SECRET' }],
30
+ });
31
+ }
32
+
33
+ @Transition({ from: 'requesting_secrets', to: 'verifying', wait: true })
34
+ async secretsSubmitted(_state: DeterministicState) {
35
+ const result = await this.getSecretKeys.call();
36
+ this.assignState({ secretKeys: result.data });
37
+ }
38
+
39
+ @Transition({ from: 'verifying', to: 'end' })
40
+ async showResult(state: DeterministicState) {
41
+ await this.documentStore.save(MarkdownDocument, {
42
+ markdown: this.render(join(__dirname, 'templates', 'secretsVerified.md'), {
43
+ secretKeys: state.secretKeys,
44
+ }),
45
+ });
46
+ }
47
+ }
@@ -0,0 +1,8 @@
1
+ # Secrets Verified
2
+
3
+ The following secrets are now stored:
4
+
5
+ {{#each secretKeys}}
6
+
7
+ - **{{this.key}}**: {{#if this.hasValue}}has value{{else}}no value{{/if}}
8
+ {{/each}}