diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml new file mode 100644 index 00000000..d8f4d081 --- /dev/null +++ b/.github/workflows/codegen.yml @@ -0,0 +1,37 @@ +name: Codegen + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +on: + workflow_dispatch: + pull_request: + paths: + - 'yarn.lock' + - 'tools/devkit/**' + - 'templates/**' + push: + branches: [main] + paths: + - 'yarn.lock' + - 'tools/devkit/**' + - 'templates/**' + +jobs: + nodejs-template-codegen-validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version-file: 'package.json' + cache: yarn + + - name: Install dependencies + run: yarn install --immutable + + - name: validate + run: yarn dev ts-mustache-codegen diff --git a/.github/workflows/nodejs-ci.yml b/.github/workflows/nodejs-ci.yml index 152fae9f..7aa28b88 100644 --- a/.github/workflows/nodejs-ci.yml +++ b/.github/workflows/nodejs-ci.yml @@ -13,6 +13,7 @@ on: - '.github/workflows/nodejs-build-common.yml' - '.github/workflows/nodejs-ci.yml' - '.github/workflows/codeql.yml' + - 'templates/**' push: branches: [main] paths: @@ -21,7 +22,7 @@ on: - '.github/workflows/nodejs-build-common.yml' - '.github/workflows/nodejs-ci.yml' - '.github/workflows/codeql.yml' - + - 'templates/**' jobs: codeql: name: nodejs-ci-codeql diff --git a/packages/nodejs/package.json b/packages/nodejs/package.json index abcb9365..3ab89115 100644 --- a/packages/nodejs/package.json +++ b/packages/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "@pleisto/node-flappy", - "version": "0.0.2", + "version": "0.0.2.beta-0", "license": "Apache-2.0", "exports": { ".": { @@ -11,6 +11,7 @@ "main": "./src/index.ts", "types": "./src/index.ts", "files": [ + "templates", "README.md", "dist" ], @@ -27,6 +28,8 @@ "dependencies": { "@pleisto/flappy-nodejs-bindings": "next", "@roarr/middleware-serialize-error": "^1.0.0", + "glob": "^10.3.3", + "mustache": "^4.2.0", "radash": "^11.0.0", "roarr": "^7.15.1", "yaml": "^2.3.3", @@ -38,6 +41,7 @@ "openai": "^4.12.4" }, "devDependencies": { + "@types/mustache": "^4", "@vitest/coverage-v8": "^0.34.6", "openai": "^4.12.4", "vitest": "^0.34.6" diff --git a/packages/nodejs/src/features/codeInterpreter.ts b/packages/nodejs/src/features/codeInterpreter.ts index 65479c65..4a107d63 100644 --- a/packages/nodejs/src/features/codeInterpreter.ts +++ b/packages/nodejs/src/features/codeInterpreter.ts @@ -10,6 +10,7 @@ import { } from '../flappy-feature.interface' import { evalPythonCode } from '@pleisto/flappy-nodejs-bindings' import { log } from '../utils' +import { templateRenderer } from '../renderer' export const codeInterpreterType = 'codeInterpreter' @@ -50,11 +51,7 @@ export class CodeInterpreter< TReturn extends typeof CodeInterpreterOutputZ > extends FlappyFeatureBase> { public override buildDescription(): string { - return ` - An safe sandbox that only support the built-in library. The execution time is limited to 120 seconds. The task is to define a function named "main" that doesn't take any parameters. The output should be a String. Network access is ${ - this.options?.enableNetwork ? 'enabled' : 'disabled' - } - `.trim() + return templateRenderer('features/codeInterpreter/description', { enabled: this.options?.enableNetwork }) } public override async call(_agent: FlappyAgentInterface, args: z.infer): Promise> { @@ -66,7 +63,7 @@ export class CodeInterpreter< log.debug({ code }, 'Generated Code:') const result = await evalPythonCode( - `${code}\nprint(main())`, + templateRenderer('features/codeInterpreter/evalCode', { code }), this.options?.enableNetwork ?? false, Object.entries(this.options?.env ?? {}), codeInterpreterGlobalCacheDirectory diff --git a/packages/nodejs/src/features/synthesized.ts b/packages/nodejs/src/features/synthesized.ts index 1c6152db..eda04367 100644 --- a/packages/nodejs/src/features/synthesized.ts +++ b/packages/nodejs/src/features/synthesized.ts @@ -6,6 +6,7 @@ import { type JsonObject } from 'roarr/dist/types' import { type FlappyFeatureMetadataBase, type CreateFunction } from '../flappy-feature.interface' import { FlappyFeatureBase } from './base' import { type FlappyAgentInterface } from '..' +import { templateRenderer } from '../renderer' const extractSchema = (schema: any, prop: string): string => JSON.stringify(omit(schema.parameters.properties[prop], ['description'])) @@ -27,23 +28,18 @@ export class SynthesizedFunction< TReturn extends z.ZodType > extends FlappyFeatureBase> { public override async call(agent: FlappyAgentInterface, args: z.infer): Promise> { - const describe = this.define.description + const describe = this.define.description ?? '' const returnTypeSchema = extractSchema(this.callingSchema, 'returnType') const argsSchema = extractSchema(this.callingSchema, 'args') const prompt = (args as any) instanceof Object ? JSON.stringify(args) : args const originalRequestMessage: ChatMLMessage[] = [ { role: 'system', - content: `${describe} - User request according to the following JSON Schema: - ${argsSchema} - - Translate it into JSON objects according to the following JSON Schema: - ${returnTypeSchema}` + content: templateRenderer('features/synthesized/systemMessage', { describe, argsSchema, returnTypeSchema }) }, { role: 'user', - content: `user request:${prompt}\n\njson object:` + content: templateRenderer('features/synthesized/userMessage', { prompt }) } ] let requestMessage = originalRequestMessage @@ -69,14 +65,11 @@ export class SynthesizedFunction< ...originalRequestMessage, { role: 'assistant', - content: result?.data ?? '' + content: result.data }, { role: 'user', - content: `You response is invalid for the following reason: - ${(err as Error).message} - - Please try again.` + content: templateRenderer('error/retry', { message: (err as Error).message }) } ] } diff --git a/packages/nodejs/src/flappy-agent.test.ts b/packages/nodejs/src/flappy-agent.test.ts index a6912507..a65af147 100644 --- a/packages/nodejs/src/flappy-agent.test.ts +++ b/packages/nodejs/src/flappy-agent.test.ts @@ -4,7 +4,6 @@ import { createFlappyAgent } from './flappy-agent' import { LLMBase } from './llms/llm-base' import { type ChatMLMessage, type GenerateConfig, type ChatMLResponse } from './llms/interface' import { type IsNever, z } from './flappy-type' -import { env } from 'node:process' import { createCodeInterpreter, createInvokeFunction, createSynthesizedFunction } from './features' import { type FindFlappyFeature } from './flappy-feature' import { type FlappyFeatureDefinitions } from './flappy-feature.interface' @@ -50,9 +49,9 @@ test('create flappy agent normally', async () => { expect(agent.executePlanSystemMessage().content).toMatchInlineSnapshot(` "You are an AI assistant that makes step-by-step plans to solve problems, utilizing external functions. Each step entails one plan followed by a function-call, which will later be executed to gather args for that step. - Make as few plans as possible if it can solve the problem. - The functions list is described using the following YAML schema array: - - name: synthesizedFunction + Make as few plans as possible if it can solve the problem. + The functions list is described using the following YAML schema array: + - name: synthesizedFunction description: synthesizedFunction parameters: type: object @@ -83,8 +82,8 @@ test('create flappy agent normally', async () => { description: Function return type - Your specified plans should be output as JSON object array and adhere to the following JSON schema: - { + Your specified plans should be output as JSON object array and adhere to the following JSON schema: + { \\"type\\": \\"array\\", \\"items\\": { \\"type\\": \\"object\\", @@ -118,7 +117,7 @@ test('create flappy agent normally', async () => { \\"description\\": \\"An array storing the steps.\\" } - Only the listed functions are allowed to be used." + Only the listed functions are allowed to be used." `) type Features = (typeof agent)['config']['features'] diff --git a/packages/nodejs/src/flappy-agent.ts b/packages/nodejs/src/flappy-agent.ts index 261f2ab4..83d3b38f 100644 --- a/packages/nodejs/src/flappy-agent.ts +++ b/packages/nodejs/src/flappy-agent.ts @@ -6,6 +6,7 @@ import { z } from './flappy-type' import { convertJsonToYaml, zodToCleanJsonSchema, log } from './utils' import { type FindFlappyFeature, type FlappyFeatureNames, type AnyFlappyFeature } from './flappy-feature' import { type JsonObject } from 'roarr/dist/types' +import { templateRenderer } from './renderer' // eslint-disable-next-line @typescript-eslint/explicit-function-return-type const lanOutputSchema = (enableCoT: boolean) => { @@ -87,15 +88,7 @@ export class FlappyAgent< const returnSchema = JSON.stringify(zodToCleanJsonSchema(zodSchema), null, 4) return { role: 'system', - content: `You are an AI assistant that makes step-by-step plans to solve problems, utilizing external functions. Each step entails one plan followed by a function-call, which will later be executed to gather args for that step. - Make as few plans as possible if it can solve the problem. - The functions list is described using the following YAML schema array: - ${functions} - - Your specified plans should be output as JSON object array and adhere to the following JSON schema: - ${returnSchema} - - Only the listed functions are allowed to be used.` + content: templateRenderer('agent/systemMessage', { functions, returnSchema }) } } @@ -110,7 +103,7 @@ export class FlappyAgent< const zodSchema = lanOutputSchema(enableCot) const originalRequestMessage: ChatMLMessage[] = [ this.executePlanSystemMessage(enableCot), - { role: 'user', content: `Prompt: ${prompt}\n\nPlan array:` } + { role: 'user', content: templateRenderer('agent/userMessage', { prompt }) } ] let requestMessage = originalRequestMessage let plan: any[] = [] @@ -150,10 +143,7 @@ export class FlappyAgent< }, { role: 'user', - content: `You response is invalid for the following reason: - ${(err as Error).message} - - Please try again.` + content: templateRenderer('error/retry', { message: (err as Error).message }) } ] } diff --git a/packages/nodejs/src/renderer/index.ts b/packages/nodejs/src/renderer/index.ts new file mode 100644 index 00000000..02d59c96 --- /dev/null +++ b/packages/nodejs/src/renderer/index.ts @@ -0,0 +1 @@ +export * from './renderer' diff --git a/packages/nodejs/src/renderer/mustacheTypes.ts b/packages/nodejs/src/renderer/mustacheTypes.ts new file mode 100644 index 00000000..4cdf2074 --- /dev/null +++ b/packages/nodejs/src/renderer/mustacheTypes.ts @@ -0,0 +1,51 @@ +type MustacheValue = string | number | boolean + +type MustacheRecord = T + +type MustacheSection = T[] | T + +interface Test_ping { + name: MustacheValue +} + +interface Error_retry { + message: MustacheValue +} + +interface Agent_userMessage { + prompt: MustacheValue +} + +interface Agent_systemMessage { + functions: MustacheValue + returnSchema: MustacheValue +} + +interface Features_synthesized_userMessage { + prompt: MustacheValue +} + +interface Features_synthesized_systemMessage { + describe: MustacheValue + argsSchema: MustacheValue + returnTypeSchema: MustacheValue +} + +interface Features_codeInterpreter_evalCode { + code: MustacheValue +} + +interface Features_codeInterpreter_description { + enabled?: MustacheValue +} + +export type TemplateMap = { + 'test/ping': Test_ping, + 'error/retry': Error_retry, + 'agent/userMessage': Agent_userMessage, + 'agent/systemMessage': Agent_systemMessage, + 'features/synthesized/userMessage': Features_synthesized_userMessage, + 'features/synthesized/systemMessage': Features_synthesized_systemMessage, + 'features/codeInterpreter/evalCode': Features_codeInterpreter_evalCode, + 'features/codeInterpreter/description': Features_codeInterpreter_description, +} \ No newline at end of file diff --git a/packages/nodejs/src/renderer/renderer.test.ts b/packages/nodejs/src/renderer/renderer.test.ts new file mode 100644 index 00000000..5c40cee4 --- /dev/null +++ b/packages/nodejs/src/renderer/renderer.test.ts @@ -0,0 +1,9 @@ +import { expect, test, describe } from 'vitest' +import { templateRenderer } from './renderer' + +describe('renderer', () => { + test('ok', () => { + const result = templateRenderer('test/ping', { name: 'foo' }) + expect(result).toEqual('foo pong') + }) +}) diff --git a/packages/nodejs/src/renderer/renderer.ts b/packages/nodejs/src/renderer/renderer.ts new file mode 100644 index 00000000..f36c542a --- /dev/null +++ b/packages/nodejs/src/renderer/renderer.ts @@ -0,0 +1,31 @@ +import { type TemplateMap } from './mustacheTypes' +import { globSync } from 'glob' +import path from 'path' +import fs from 'fs' +import Mustache from 'mustache' + +const TemplateFolderPath = './templates' +const MUSTACHE_EXTENSION = '.mustache' + +const files = globSync(path.join(TemplateFolderPath, `**/*${MUSTACHE_EXTENSION}`)) + +if (files.length === 0) throw new Error('template not found') + +const contents = files.map(f => fs.readFileSync(f, { encoding: 'utf8' })) + +const templates = Object.fromEntries( + files.map((f, i) => [path.relative(TemplateFolderPath, f).replace(MUSTACHE_EXTENSION, ''), contents[i]]) +) + +export type TemplateRenderer = (templateName: K, params: TemplateMap[K]) => string + +export type RendererType = { + [K in keyof TemplateMap]: (params: TemplateMap[K]) => string +} + +export const templateRenderer: TemplateRenderer = (name, params) => { + const template = templates[name] + if (!template) throw new Error(`Unknown template '${String(name)}'`) + + return Mustache.render(template, params, undefined, { escape: value => value }) +} diff --git a/packages/nodejs/templates b/packages/nodejs/templates new file mode 120000 index 00000000..7cb455a6 --- /dev/null +++ b/packages/nodejs/templates @@ -0,0 +1 @@ +../../templates/ \ No newline at end of file diff --git a/renovate.json b/renovate.json index b8e2824e..3deb6d8b 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,6 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "commitMessage": "chore(deps): update deps", + "commitMessage": "chore(deps): upgrade dependencies", "extends": [ "config:recommended", "group:all" @@ -12,5 +12,7 @@ "schedule": [ "on monday and thursday" ], - "ignoreDeps": [] + "ignoreDeps": [ + "chalk" + ] } \ No newline at end of file diff --git a/templates/agent/systemMessage.mustache b/templates/agent/systemMessage.mustache new file mode 100644 index 00000000..9165f00a --- /dev/null +++ b/templates/agent/systemMessage.mustache @@ -0,0 +1,9 @@ +You are an AI assistant that makes step-by-step plans to solve problems, utilizing external functions. Each step entails one plan followed by a function-call, which will later be executed to gather args for that step. +Make as few plans as possible if it can solve the problem. +The functions list is described using the following YAML schema array: +{{functions}} + +Your specified plans should be output as JSON object array and adhere to the following JSON schema: +{{returnSchema}} + +Only the listed functions are allowed to be used. \ No newline at end of file diff --git a/templates/agent/userMessage.mustache b/templates/agent/userMessage.mustache new file mode 100644 index 00000000..6e87628d --- /dev/null +++ b/templates/agent/userMessage.mustache @@ -0,0 +1,3 @@ +Prompt: {{prompt}} + +Plan array: \ No newline at end of file diff --git a/templates/error/retry.mustache b/templates/error/retry.mustache new file mode 100644 index 00000000..042467db --- /dev/null +++ b/templates/error/retry.mustache @@ -0,0 +1,4 @@ +Your response is invalid for the following reason: +{{message}} + +Please try again. \ No newline at end of file diff --git a/templates/features/codeInterpreter/description.mustache b/templates/features/codeInterpreter/description.mustache new file mode 100644 index 00000000..4dc1e9c0 --- /dev/null +++ b/templates/features/codeInterpreter/description.mustache @@ -0,0 +1 @@ +An safe sandbox that only support the built-in library. The execution time is limited to 120 seconds. The task is to define a function named "main" that doesn't take any parameters. The output should be a String. Network access is {{#enabled}}enabled{{/enabled}}{{^enabled}}disabled{{/enabled}} \ No newline at end of file diff --git a/templates/features/codeInterpreter/evalCode.mustache b/templates/features/codeInterpreter/evalCode.mustache new file mode 100644 index 00000000..102ee08f --- /dev/null +++ b/templates/features/codeInterpreter/evalCode.mustache @@ -0,0 +1,2 @@ +{{code}} +print(main()) \ No newline at end of file diff --git a/templates/features/synthesized/systemMessage.mustache b/templates/features/synthesized/systemMessage.mustache new file mode 100644 index 00000000..79e527e1 --- /dev/null +++ b/templates/features/synthesized/systemMessage.mustache @@ -0,0 +1,6 @@ +{{describe}} +User request according to the following JSON Schema: +{{argsSchema}} + +Translate it into JSON objects according to the following JSON Schema: +{{returnTypeSchema}} \ No newline at end of file diff --git a/templates/features/synthesized/userMessage.mustache b/templates/features/synthesized/userMessage.mustache new file mode 100644 index 00000000..bd5bc38a --- /dev/null +++ b/templates/features/synthesized/userMessage.mustache @@ -0,0 +1,3 @@ +user request:{{prompt}} + +json object: \ No newline at end of file diff --git a/templates/test/ping.mustache b/templates/test/ping.mustache new file mode 100644 index 00000000..aaf48a6e --- /dev/null +++ b/templates/test/ping.mustache @@ -0,0 +1 @@ +{{name}} pong \ No newline at end of file diff --git a/tools/devkit/package.json b/tools/devkit/package.json index 4d329712..ee5fecd3 100644 --- a/tools/devkit/package.json +++ b/tools/devkit/package.json @@ -20,8 +20,9 @@ "@angular-devkit/core": "^16.2.7", "@angular-devkit/schematics": "^16.2.7", "@angular-devkit/schematics-cli": "^16.2.7", - "chalk": "^5.0.0", + "chalk": "^4.1.2", "jsonc": "^2.0.0", + "ts-mustache": "^0.0.2", "ts-node": "^10.9.1", "typescript": "^5.2.2", "v8-compile-cache": "^2.4.0", diff --git a/tools/devkit/src/commands/is-ci.ts b/tools/devkit/src/commands/is-ci.ts index 1d39dbbf..e74a1bc4 100644 --- a/tools/devkit/src/commands/is-ci.ts +++ b/tools/devkit/src/commands/is-ci.ts @@ -4,7 +4,7 @@ import { env, exit } from 'node:process' /** * Returns true if the current process is running in a CI environment. */ -const isCI = !!( +export const isCI = !!( env.CI || // Travis CI, CircleCI, AppVeyor, GitHub Actions env.CONTINUOUS_INTEGRATION || // Travis CI, CircleCI env.BUILD_NUMBER || // Jenkins, TeamCity diff --git a/tools/devkit/src/commands/mod.ts b/tools/devkit/src/commands/mod.ts index 23915e7a..06399842 100644 --- a/tools/devkit/src/commands/mod.ts +++ b/tools/devkit/src/commands/mod.ts @@ -1,4 +1,5 @@ import * as isCI from './is-ci' import * as generate from './generate' +import * as tsMustacheCodegen from './ts-mustache-codegen' -export const commands = [isCI, generate] +export const commands = [isCI, generate, tsMustacheCodegen] diff --git a/tools/devkit/src/commands/ts-mustache-codegen.ts b/tools/devkit/src/commands/ts-mustache-codegen.ts new file mode 100644 index 00000000..642b6cb7 --- /dev/null +++ b/tools/devkit/src/commands/ts-mustache-codegen.ts @@ -0,0 +1,32 @@ +import { DefaultLoader, Declarer } from 'ts-mustache' +import { type CommandModule } from 'yargs' +import fs from 'fs' +import { monoRepoRootPath } from '../utils' +import { chdir, exit } from 'process' +import { isCI } from './is-ci' + +export const command = 'ts-mustache-codegen' +export const describe = 'Generate typescript code for mustache templates.' +export const builder: CommandModule['builder'] = {} +export const handler: CommandModule['handler'] = async (): Promise => { + chdir(monoRepoRootPath) + const loader = new DefaultLoader({ + dir: './templates' + }) + + const TargetPath = './packages/nodejs/src/renderer/mustacheTypes.ts' + + // Generate typedefs + const declarer = new Declarer(loader) + const types = await declarer.declare() + const data = fs.readFileSync(TargetPath).toString() + + if (isCI) { + if (data !== types) exit(1) + console.log('codegen validate ok') + } else { + fs.writeFileSync(TargetPath, types) + } + + exit(0) +} diff --git a/yarn.lock b/yarn.lock index 983a3934..394d5a34 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3061,8 +3061,9 @@ __metadata: "@swc/helpers": "npm:^0.5.3" "@types/node": "npm:^20.8.7" "@types/yargs": "npm:^17.0.29" - chalk: "npm:^5.0.0" + chalk: "npm:^4.1.2" jsonc: "npm:^2.0.0" + ts-mustache: "npm:^0.0.2" ts-node: "npm:^10.9.1" typescript: "npm:^5.2.2" v8-compile-cache: "npm:^2.4.0" @@ -3213,7 +3214,10 @@ __metadata: "@pleisto/flappy-nodejs-bindings": "npm:next" "@roarr/cli": "npm:^5.12.3" "@roarr/middleware-serialize-error": "npm:^1.0.0" + "@types/mustache": "npm:^4" "@vitest/coverage-v8": "npm:^0.34.6" + glob: "npm:^10.3.3" + mustache: "npm:^4.2.0" openai: "npm:^4.12.4" radash: "npm:^11.0.0" roarr: "npm:^7.15.1" @@ -4072,6 +4076,13 @@ __metadata: languageName: node linkType: hard +"@types/mustache@npm:^4": + version: 4.2.4 + resolution: "@types/mustache@npm:4.2.4" + checksum: 11cb82b85095814df1b7ba747e4cbb8e35cf1701eff557c9d91749d6e9208a66da058a2b0ecea7e7749f5dbcd4ed31ab4996a8a51c7d8ddcb50ee04d4a865358 + languageName: node + linkType: hard + "@types/node-fetch@npm:^2.6.4": version: 2.6.5 resolution: "@types/node-fetch@npm:2.6.5" @@ -5821,7 +5832,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:5.3.0, chalk@npm:^5.0.0, chalk@npm:^5.0.1, chalk@npm:^5.2.0": +"chalk@npm:5.3.0, chalk@npm:^5.0.1, chalk@npm:^5.2.0": version: 5.3.0 resolution: "chalk@npm:5.3.0" checksum: 8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09 @@ -8939,7 +8950,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2": +"glob@npm:^10.2.2, glob@npm:^10.3.3": version: 10.3.10 resolution: "glob@npm:10.3.10" dependencies: @@ -12183,7 +12194,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.6, minimist@npm:^1.2.7": +"minimist@npm:^1.2.0, minimist@npm:^1.2.6, minimist@npm:^1.2.7, minimist@npm:^1.2.8": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 @@ -12353,6 +12364,15 @@ __metadata: languageName: node linkType: hard +"mustache@npm:^4.2.0": + version: 4.2.0 + resolution: "mustache@npm:4.2.0" + bin: + mustache: bin/mustache + checksum: 1f8197e8a19e63645a786581d58c41df7853da26702dbc005193e2437c98ca49b255345c173d50c08fe4b4dbb363e53cb655ecc570791f8deb09887248dd34a2 + languageName: node + linkType: hard + "mute-stream@npm:0.0.8": version: 0.0.8 resolution: "mute-stream@npm:0.0.8" @@ -15966,6 +15986,13 @@ __metadata: languageName: node linkType: hard +"ts-directed-graph@npm:^0.0.1": + version: 0.0.1 + resolution: "ts-directed-graph@npm:0.0.1" + checksum: c4fd8be724a5e532846d15af1ed808fa7c8e3e569f06f9d87a2ee015a1c3c57a3dfb542c07533fa058af58430599d0443f8e9c0e0899fe821ba55a2ef08f1ff9 + languageName: node + linkType: hard + "ts-error@npm:^1.0.6": version: 1.0.6 resolution: "ts-error@npm:1.0.6" @@ -15973,6 +16000,20 @@ __metadata: languageName: node linkType: hard +"ts-mustache@npm:^0.0.2": + version: 0.0.2 + resolution: "ts-mustache@npm:0.0.2" + dependencies: + glob: "npm:^10.3.3" + minimist: "npm:^1.2.8" + mustache: "npm:^4.2.0" + ts-directed-graph: "npm:^0.0.1" + bin: + ts-mustache: dist/cli/declarations.js + checksum: 92df10196c2684417eaa8a6350ebe5389a00959f62b91b128f00852471a03ca9492d0f6624fc725d33934888973cf97c3ece83d9eca8f22b696286e5d3038efc + languageName: node + linkType: hard + "ts-node@npm:^10.8.1, ts-node@npm:^10.9.1": version: 10.9.1 resolution: "ts-node@npm:10.9.1"