Skip to content

Commit d5c2217

Browse files
authored
Merge pull request #166 from nanoapi-io/feature/ai-labeling
implement AI labeling to generate description for manifest
2 parents 54e2d1c + 3624cbb commit d5c2217

File tree

25 files changed

+1296
-55
lines changed

25 files changed

+1296
-55
lines changed

.github/workflows/lint_test_compile.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
- name: Set up Deno
1515
uses: denoland/setup-deno@v2
1616
with:
17-
deno-version: "2.x"
17+
deno-version: "2.4.0"
1818

1919
- name: Install dependencies
2020
run: |
@@ -35,7 +35,7 @@ jobs:
3535
- name: Set up Node.js
3636
uses: denoland/setup-deno@v2
3737
with:
38-
deno-version: "2.x"
38+
deno-version: "2.4.0"
3939

4040
- name: Install dependencies
4141
run: |
@@ -53,7 +53,7 @@ jobs:
5353
- name: Set up Node.js
5454
uses: denoland/setup-deno@v2
5555
with:
56-
deno-version: "2.x"
56+
deno-version: "2.4.0"
5757

5858
- name: Install dependencies
5959
run: |

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Set up Deno
1717
uses: denoland/setup-deno@v2
1818
with:
19-
deno-version: "2.3.5"
19+
deno-version: "2.4.0"
2020

2121
- name: Get new version and bump deno.json
2222
id: get_version

deno.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
{
2-
"version": "1.0.13",
2+
"version": "1.0.14",
33
"name": "@napi/cli",
44
"exports": "./src/index.ts",
55
"nodeModulesDir": "auto",
66
"lock": false,
77
"imports": {
88
"@inquirer/prompts": "npm:@inquirer/prompts@^7.5.3",
9+
"@langchain/anthropic": "npm:@langchain/anthropic@^0.3.23",
10+
"@langchain/core": "npm:@langchain/core@^0.3.61",
11+
"@langchain/google-genai": "npm:@langchain/google-genai@^0.2.14",
12+
"@langchain/google-vertexai": "npm:@langchain/google-vertexai@^0.2.14",
13+
"@langchain/langgraph": "npm:@langchain/langgraph@^0.3.5",
14+
"@langchain/openai": "npm:@langchain/openai@^0.5.15",
915
"@oak/oak": "jsr:@oak/oak@^17.1.4",
1016
"@std/expect": "jsr:@std/expect@^1.0.16",
1117
"@std/path": "jsr:@std/path@^1.0.9",

examples/csharp/EndpointExample/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
"$schema": "https://json.schemastore.org/launchsettings.json",
33
"profiles": {
44
"http": {

examples/java/websocket/pom.xml

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,51 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
3-
<modelVersion>4.0.0</modelVersion>
4-
<artifactId>websocket</artifactId>
5-
<parent>
6-
<!-- Your own application should inherit from spring-boot-starter-parent -->
7-
<groupId>org.springframework.boot</groupId>
8-
<artifactId>spring-boot-starter-parent</artifactId>
9-
<version>1.0.2.RELEASE</version>
10-
</parent>
11-
<groupId>napi</groupId>
12-
<name>Spring Boot WebSocket Sample</name>
13-
<description>Spring Boot WebSocket Sample</description>
14-
<version>1.0-SNAPSHOT</version>
15-
<url>http://projects.spring.io/spring-boot/</url>
16-
<organization>
17-
<name>Pivotal Software, Inc.</name>
18-
<url>http://www.spring.io</url>
19-
</organization>
20-
<properties>
21-
<main.basedir>${basedir}/../..</main.basedir>
22-
<java.version>1.7</java.version>
23-
</properties>
24-
<dependencies>
25-
<dependency>
26-
<groupId>org.springframework.boot</groupId>
27-
<artifactId>spring-boot-starter-websocket</artifactId>
28-
</dependency>
29-
<dependency>
30-
<groupId>org.springframework.boot</groupId>
31-
<artifactId>spring-boot-starter-actuator</artifactId>
32-
</dependency>
33-
<dependency>
34-
<groupId>org.springframework.boot</groupId>
35-
<artifactId>spring-boot-starter-test</artifactId>
36-
<scope>test</scope>
37-
</dependency>
38-
</dependencies>
39-
<build>
40-
<plugins>
41-
<plugin>
42-
<groupId>org.springframework.boot</groupId>
43-
<artifactId>spring-boot-maven-plugin</artifactId>
44-
</plugin>
45-
</plugins>
46-
</build>
2+
<project
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
6+
>
7+
<modelVersion>4.0.0</modelVersion>
8+
<artifactId>websocket</artifactId>
9+
<parent>
10+
<!-- Your own application should inherit from spring-boot-starter-parent -->
11+
<groupId>org.springframework.boot</groupId>
12+
<artifactId>spring-boot-starter-parent</artifactId>
13+
<version>1.0.2.RELEASE</version>
14+
</parent>
15+
<groupId>napi</groupId>
16+
<name>Spring Boot WebSocket Sample</name>
17+
<description>Spring Boot WebSocket Sample</description>
18+
<version>1.0-SNAPSHOT</version>
19+
<url>http://projects.spring.io/spring-boot/</url>
20+
<organization>
21+
<name>Pivotal Software, Inc.</name>
22+
<url>http://www.spring.io</url>
23+
</organization>
24+
<properties>
25+
<main.basedir>${basedir}/../..</main.basedir>
26+
<java.version>1.7</java.version>
27+
</properties>
28+
<dependencies>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-websocket</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.springframework.boot</groupId>
35+
<artifactId>spring-boot-starter-actuator</artifactId>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.springframework.boot</groupId>
39+
<artifactId>spring-boot-starter-test</artifactId>
40+
<scope>test</scope>
41+
</dependency>
42+
</dependencies>
43+
<build>
44+
<plugins>
45+
<plugin>
46+
<groupId>org.springframework.boot</groupId>
47+
<artifactId>spring-boot-maven-plugin</artifactId>
48+
</plugin>
49+
</plugins>
50+
</build>
4751
</project>

src/cli/handlers/init/index.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ import {
2020
import { ApiService } from "../../../apiService/index.ts";
2121
import type { globalConfigSchema } from "../../middlewares/globalConfig.ts";
2222
import { isAuthenticatedMiddleware } from "../../middlewares/isAuthenticated.ts";
23+
import {
24+
ANTHROPIC_PROVIDER,
25+
GOOGLE_PROVIDER,
26+
OPENAI_PROVIDER,
27+
} from "../../../manifest/dependencyManifest/labeling/model.ts";
2328

2429
function builder(
2530
yargs: Arguments & {
@@ -1031,6 +1036,61 @@ export async function generateConfig(
10311036
// Show final file selection to the user
10321037
showFinalFileSelection(workDir, includePatterns, excludePatterns);
10331038

1039+
// Labeling configuration
1040+
console.info("\n🏷️ LABELING CONFIGURATION");
1041+
console.info(
1042+
"Labeling helps categorize and organize your code dependencies using AI models.",
1043+
);
1044+
1045+
const enableLabeling = await confirm({
1046+
message: "Would you like to enable AI-powered labeling?",
1047+
default: false,
1048+
});
1049+
1050+
let labelingConfig:
1051+
| z.infer<typeof localConfigSchema>["labeling"]
1052+
| undefined = undefined;
1053+
1054+
if (enableLabeling) {
1055+
console.info("\n🤖 AI MODEL SELECTION");
1056+
console.info(
1057+
"Choose an AI provider for labeling your dependencies:",
1058+
);
1059+
1060+
const modelProvider = await select({
1061+
message: "Select AI model provider:",
1062+
choices: [
1063+
{ name: "OpenAI (GPT-4o-mini)", value: OPENAI_PROVIDER },
1064+
{ name: "Google (Gemini 2.5 Flash)", value: GOOGLE_PROVIDER },
1065+
{ name: "Anthropic (Claude 3.5 Sonnet)", value: ANTHROPIC_PROVIDER },
1066+
],
1067+
}) as
1068+
| typeof OPENAI_PROVIDER
1069+
| typeof GOOGLE_PROVIDER
1070+
| typeof ANTHROPIC_PROVIDER;
1071+
1072+
const maxConcurrency = await input({
1073+
message: "Enter maximum concurrent requests (leave empty for unlimited):",
1074+
validate: (value) => {
1075+
if (!value.trim()) return true; // Allow empty for unlimited
1076+
const num = parseInt(value);
1077+
if (isNaN(num) || num <= 0) {
1078+
return "Please enter a positive number or leave empty for unlimited";
1079+
}
1080+
return true;
1081+
},
1082+
});
1083+
1084+
labelingConfig = {
1085+
modelProvider,
1086+
maxConcurrency: maxConcurrency.trim()
1087+
? parseInt(maxConcurrency)
1088+
: undefined,
1089+
};
1090+
1091+
console.info("✅ Labeling configuration added");
1092+
}
1093+
10341094
// Build the config object
10351095
const config: z.infer<typeof localConfigSchema> = {
10361096
language: language,
@@ -1052,5 +1112,10 @@ export async function generateConfig(
10521112
config.c = cConfig;
10531113
}
10541114

1115+
// Add labeling config if it exists
1116+
if (labelingConfig) {
1117+
config.labeling = labelingConfig;
1118+
}
1119+
10551120
return config;
10561121
}

src/cli/handlers/manifest/generate.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ function builder(
4545
}
4646
return value;
4747
},
48+
}).option("labelingApiKey", {
49+
type: "string",
50+
description: "The API key to use for the labeling",
4851
});
4952
}
5053

@@ -128,6 +131,7 @@ async function handler(
128131
branch?: string;
129132
commitSha?: string;
130133
commitShaDate?: string;
134+
labelingApiKey?: string;
131135
},
132136
) {
133137
const napiConfig = argv.napiConfig as z.infer<typeof localConfigSchema>;
@@ -217,7 +221,12 @@ async function handler(
217221

218222
console.info(`📊 Processing ${files.size} files...`);
219223

220-
const dependencyManifest = generateDependencyManifest(files, napiConfig);
224+
const dependencyManifest = await generateDependencyManifest(
225+
files,
226+
napiConfig,
227+
globalConfig,
228+
argv.labelingApiKey,
229+
);
221230

222231
// Upload manifest to API instead of writing to disk
223232
const apiService = new ApiService(

src/cli/handlers/set/apiKey.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import type { Arguments } from "yargs-types";
2+
import type { z } from "zod";
3+
import {
4+
type globalConfigSchema,
5+
setConfig,
6+
} from "../../middlewares/globalConfig.ts";
7+
import {
8+
ANTHROPIC_PROVIDER,
9+
GOOGLE_PROVIDER,
10+
type ModelProvider,
11+
OPENAI_PROVIDER,
12+
} from "../../../manifest/dependencyManifest/labeling/model.ts";
13+
import { input, select } from "@inquirer/prompts";
14+
15+
async function handler(
16+
argv: Arguments & {
17+
globalConfig: z.infer<typeof globalConfigSchema>;
18+
},
19+
) {
20+
const globalConfig = argv.globalConfig as z.infer<typeof globalConfigSchema>;
21+
22+
const provider = await select({
23+
message: "Select a provider",
24+
choices: [
25+
{ name: "Google", value: GOOGLE_PROVIDER },
26+
{ name: "OpenAI", value: OPENAI_PROVIDER },
27+
{ name: "Anthropic", value: ANTHROPIC_PROVIDER },
28+
],
29+
}) as ModelProvider;
30+
31+
const apiKey = await input({
32+
message: "Enter the API key",
33+
validate: (value) => {
34+
if (value.length === 0) {
35+
return "API key cannot be empty";
36+
}
37+
return true;
38+
},
39+
});
40+
41+
const labeling = globalConfig.labeling || { apiKeys: {} };
42+
labeling.apiKeys[provider] = apiKey;
43+
setConfig({ ...globalConfig, labeling });
44+
45+
console.info("API key set successfully");
46+
}
47+
48+
export default {
49+
command: "apiKey",
50+
describe: "set an API key for a model provider in your global config",
51+
builder: () => {},
52+
handler,
53+
};

src/cli/handlers/set/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import apiKeyHandler from "./apiKey.ts";
2+
import type { Arguments } from "yargs-types";
3+
import type { globalConfigSchema } from "../../middlewares/globalConfig.ts";
4+
import type { z } from "zod";
5+
6+
function builder(
7+
yargs: Arguments & {
8+
globalConfig: z.infer<typeof globalConfigSchema>;
9+
},
10+
) {
11+
return yargs
12+
.command(apiKeyHandler)
13+
.demandCommand(1, "You need to specify a valid command");
14+
}
15+
16+
export default {
17+
command: "set",
18+
describe: "set a value in the global config",
19+
builder,
20+
handler: () => {},
21+
};

src/cli/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
} from "./middlewares/checkVersion.ts";
66
import loginCommand from "./handlers/login/index.ts";
77
import initCommand from "./handlers/init/index.ts";
8+
import setCommand from "./handlers/set/index.ts";
89
import manifestCommand from "./handlers/manifest/index.ts";
910
import extractCommand from "./handlers/extract/index.ts";
1011
import { globalConfigMiddleware } from "./middlewares/globalConfig.ts";
@@ -27,6 +28,7 @@ export function initCli() {
2728
.middleware(globalConfigMiddleware)
2829
.command(loginCommand)
2930
.command(initCommand)
31+
.command(setCommand)
3032
.command(manifestCommand)
3133
.command(extractCommand)
3234
.demandCommand(1, "You need to specify a command")

0 commit comments

Comments
 (0)