rolax 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +5 -5
- package/package.json +1 -1
- package/src/index.ts +10 -2
- package/src/llm.ts +5 -5
- package/src/prompts.ts +1 -1
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{createRequire as
|
|
3
|
-
`);let
|
|
4
|
-
`),b=b.replace(/\\r/g,"\r");
|
|
5
|
-
Your task is to interview users and get the basic idea about the app
|
|
2
|
+
import{createRequire as d}from"node:module";var M=Object.create;var{getPrototypeOf:D,defineProperty:Z,getOwnPropertyNames:_}=Object;var h=Object.prototype.hasOwnProperty;var y=(c,g,f)=>{f=c!=null?M(D(c)):{};let R=g||!c||!c.__esModule?Z(f,"default",{value:c,enumerable:!0}):f;for(let O of _(c))if(!h.call(R,O))Z(R,O,{get:()=>c[O],enumerable:!0});return R};var F=(c,g)=>()=>(g||c((g={exports:{}}).exports,g),g.exports);var m=d(import.meta.url);var H=F((yc,t)=>{t.exports={name:"dotenv",version:"17.2.3",description:"Loads environment variables from .env file",main:"lib/main.js",types:"lib/main.d.ts",exports:{".":{types:"./lib/main.d.ts",require:"./lib/main.js",default:"./lib/main.js"},"./config":"./config.js","./config.js":"./config.js","./lib/env-options":"./lib/env-options.js","./lib/env-options.js":"./lib/env-options.js","./lib/cli-options":"./lib/cli-options.js","./lib/cli-options.js":"./lib/cli-options.js","./package.json":"./package.json"},scripts:{"dts-check":"tsc --project tests/types/tsconfig.json",lint:"standard",pretest:"npm run lint && npm run dts-check",test:"tap run tests/**/*.js --allow-empty-coverage --disable-coverage --timeout=60000","test:coverage":"tap run tests/**/*.js --show-full-coverage --timeout=60000 --coverage-report=text --coverage-report=lcov",prerelease:"npm test",release:"standard-version"},repository:{type:"git",url:"git://github.com/motdotla/dotenv.git"},homepage:"https://github.com/motdotla/dotenv#readme",funding:"https://dotenvx.com",keywords:["dotenv","env",".env","environment","variables","config","settings"],readmeFilename:"README.md",license:"BSD-2-Clause",devDependencies:{"@types/node":"^18.11.3",decache:"^4.6.2",sinon:"^14.0.1",standard:"^17.0.0","standard-version":"^9.5.0",tap:"^19.2.0",typescript:"^4.8.4"},engines:{node:">=12"},browser:{fs:!1}}});var X=F((Fc,T)=>{var z=m("fs"),Y=m("path"),l=m("os"),s=m("crypto"),r=H(),W=r.version,Q=["\uD83D\uDD10 encrypt with Dotenvx: https://dotenvx.com","\uD83D\uDD10 prevent committing .env to code: https://dotenvx.com/precommit","\uD83D\uDD10 prevent building .env in docker: https://dotenvx.com/prebuild","\uD83D\uDCE1 add observability to secrets: https://dotenvx.com/ops","\uD83D\uDC65 sync secrets across teammates & machines: https://dotenvx.com/ops","\uD83D\uDDC2️ backup and recover secrets: https://dotenvx.com/ops","✅ audit secrets and track compliance: https://dotenvx.com/ops","\uD83D\uDD04 add secrets lifecycle management: https://dotenvx.com/ops","\uD83D\uDD11 add access controls to secrets: https://dotenvx.com/ops","\uD83D\uDEE0️ run anywhere with `dotenvx run -- yourcommand`","⚙️ specify custom .env file path with { path: '/custom/path/.env' }","⚙️ enable debug logging with { debug: true }","⚙️ override existing env vars with { override: true }","⚙️ suppress all logs with { quiet: true }","⚙️ write to custom object with { processEnv: myObject }","⚙️ load multiple .env files with { path: ['.env.local', '.env'] }"];function e(){return Q[Math.floor(Math.random()*Q.length)]}function $(c){if(typeof c==="string")return!["false","0","no","off",""].includes(c.toLowerCase());return Boolean(c)}function u(){return process.stdout.isTTY}function v(c){return u()?`\x1B[2m${c}\x1B[0m`:c}var p=/(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;function o(c){let g={},f=c.toString();f=f.replace(/\r\n?/mg,`
|
|
3
|
+
`);let R;while((R=p.exec(f))!=null){let O=R[1],b=R[2]||"";b=b.trim();let j=b[0];if(b=b.replace(/^(['"`])([\s\S]*)\1$/mg,"$2"),j==='"')b=b.replace(/\\n/g,`
|
|
4
|
+
`),b=b.replace(/\\r/g,"\r");g[O]=b}return g}function cc(c){c=c||{};let g=a(c);c.path=g;let f=C.configDotenv(c);if(!f.parsed){let j=Error(`MISSING_DATA: Cannot parse ${g} for an unknown reason`);throw j.code="MISSING_DATA",j}let R=K(c).split(","),O=R.length,b;for(let j=0;j<O;j++)try{let w=R[j].trim(),A=jc(f,w);b=C.decrypt(A.ciphertext,A.key);break}catch(w){if(j+1>=O)throw w}return C.parse(b)}function gc(c){console.error(`[dotenv@${W}][WARN] ${c}`)}function I(c){console.log(`[dotenv@${W}][DEBUG] ${c}`)}function N(c){console.log(`[dotenv@${W}] ${c}`)}function K(c){if(c&&c.DOTENV_KEY&&c.DOTENV_KEY.length>0)return c.DOTENV_KEY;if(process.env.DOTENV_KEY&&process.env.DOTENV_KEY.length>0)return process.env.DOTENV_KEY;return""}function jc(c,g){let f;try{f=new URL(g)}catch(w){if(w.code==="ERR_INVALID_URL"){let A=Error("INVALID_DOTENV_KEY: Wrong format. Must be in valid uri format like dotenv://:key_1234@dotenvx.com/vault/.env.vault?environment=development");throw A.code="INVALID_DOTENV_KEY",A}throw w}let R=f.password;if(!R){let w=Error("INVALID_DOTENV_KEY: Missing key part");throw w.code="INVALID_DOTENV_KEY",w}let O=f.searchParams.get("environment");if(!O){let w=Error("INVALID_DOTENV_KEY: Missing environment part");throw w.code="INVALID_DOTENV_KEY",w}let b=`DOTENV_VAULT_${O.toUpperCase()}`,j=c.parsed[b];if(!j){let w=Error(`NOT_FOUND_DOTENV_ENVIRONMENT: Cannot locate environment ${b} in your .env.vault file.`);throw w.code="NOT_FOUND_DOTENV_ENVIRONMENT",w}return{ciphertext:j,key:R}}function a(c){let g=null;if(c&&c.path&&c.path.length>0)if(Array.isArray(c.path)){for(let f of c.path)if(z.existsSync(f))g=f.endsWith(".vault")?f:`${f}.vault`}else g=c.path.endsWith(".vault")?c.path:`${c.path}.vault`;else g=Y.resolve(process.cwd(),".env.vault");if(z.existsSync(g))return g;return null}function B(c){return c[0]==="~"?Y.join(l.homedir(),c.slice(1)):c}function Rc(c){let g=$(process.env.DOTENV_CONFIG_DEBUG||c&&c.debug),f=$(process.env.DOTENV_CONFIG_QUIET||c&&c.quiet);if(g||!f)N("Loading env from encrypted .env.vault");let R=C._parseVault(c),O=process.env;if(c&&c.processEnv!=null)O=c.processEnv;return C.populate(O,R,c),{parsed:R}}function fc(c){let g=Y.resolve(process.cwd(),".env"),f="utf8",R=process.env;if(c&&c.processEnv!=null)R=c.processEnv;let O=$(R.DOTENV_CONFIG_DEBUG||c&&c.debug),b=$(R.DOTENV_CONFIG_QUIET||c&&c.quiet);if(c&&c.encoding)f=c.encoding;else if(O)I("No encoding is specified. UTF-8 is used by default");let j=[g];if(c&&c.path)if(!Array.isArray(c.path))j=[B(c.path)];else{j=[];for(let S of c.path)j.push(B(S))}let w,A={};for(let S of j)try{let x=C.parse(z.readFileSync(S,{encoding:f}));C.populate(A,x,c)}catch(x){if(O)I(`Failed to load ${S} ${x.message}`);w=x}let J=C.populate(R,A,c);if(O=$(R.DOTENV_CONFIG_DEBUG||O),b=$(R.DOTENV_CONFIG_QUIET||b),O||!b){let S=Object.keys(J).length,x=[];for(let G of j)try{let U=Y.relative(process.cwd(),G);x.push(U)}catch(U){if(O)I(`Failed to load ${G} ${U.message}`);w=U}N(`injecting env (${S}) from ${x.join(",")} ${v(`-- tip: ${e()}`)}`)}if(w)return{parsed:A,error:w};else return{parsed:A}}function wc(c){if(K(c).length===0)return C.configDotenv(c);let g=a(c);if(!g)return gc(`You set DOTENV_KEY but you are missing a .env.vault file at ${g}. Did you forget to build it?`),C.configDotenv(c);return C._configVault(c)}function Oc(c,g){let f=Buffer.from(g.slice(-64),"hex"),R=Buffer.from(c,"base64"),O=R.subarray(0,12),b=R.subarray(-16);R=R.subarray(12,-16);try{let j=s.createDecipheriv("aes-256-gcm",f,O);return j.setAuthTag(b),`${j.update(R)}${j.final()}`}catch(j){let w=j instanceof RangeError,A=j.message==="Invalid key length",J=j.message==="Unsupported state or unable to authenticate data";if(w||A){let S=Error("INVALID_DOTENV_KEY: It must be 64 characters long (or more)");throw S.code="INVALID_DOTENV_KEY",S}else if(J){let S=Error("DECRYPTION_FAILED: Please check your DOTENV_KEY");throw S.code="DECRYPTION_FAILED",S}else throw j}}function bc(c,g,f={}){let R=Boolean(f&&f.debug),O=Boolean(f&&f.override),b={};if(typeof g!=="object"){let j=Error("OBJECT_REQUIRED: Please check the processEnv argument being passed to populate");throw j.code="OBJECT_REQUIRED",j}for(let j of Object.keys(g))if(Object.prototype.hasOwnProperty.call(c,j)){if(O===!0)c[j]=g[j],b[j]=g[j];if(R)if(O===!0)I(`"${j}" is already defined and WAS overwritten`);else I(`"${j}" is already defined and was NOT overwritten`)}else c[j]=g[j],b[j]=g[j];return b}var C={configDotenv:fc,_configVault:Rc,_parseVault:cc,config:wc,decrypt:Oc,parse:o,populate:bc};Fc.configDotenv=C.configDotenv;Fc._configVault=C._configVault;Fc._parseVault=C._parseVault;Fc.config=C.config;Fc.decrypt=C.decrypt;Fc.parse=C.parse;Fc.populate=C.populate;T.exports=C});var P=y(X(),1);import{platform as Uc}from"os";import{join as mc}from"path";var L=y(X(),1);L.default.config();var i={openai:{name:"openai",apiKey:process.env.OPENAI_API_KEY||"",model:process.env.OPENAI_MODEL||"gpt-3.5-turbo",url:"https://api.openai.com/v1/chat/completions"},openrouter:{name:"openrouter",apiKey:process.env.OPENROUTER_API_KEY||"",model:process.env.OPENROUTER_MODEL||"google/gemini-2.5-flash-lite",url:"https://openrouter.ai/api/v1/chat/completions"}},E=["openrouter","openai"];var V={system:`You are an expert app development assistant.
|
|
5
|
+
Your task is to interview users and get the basic idea about the app.
|
|
6
6
|
Intension is to gather AGENTS.md and TODOS.md required to build the app.
|
|
7
7
|
Ask relevant questions to understand the app idea clearly.
|
|
8
8
|
Once you have enough information, generate AGENTS.md and TODOS.md files.
|
|
@@ -12,4 +12,4 @@ import{createRequire as t}from"node:module";var D=Object.create;var{getPrototype
|
|
|
12
12
|
"todos": string
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
`};import
|
|
15
|
+
`};import Jc from"node:readline/promises";async function k(c,g){let f={"Content-Type":"application/json",Authorization:`Bearer ${c.apiKey}`};if(c.name==="openrouter")f["HTTP-Referer"]=process.env.OPENROUTER_REFERER||"http://localhost",f["X-Title"]=process.env.OPENROUTER_APP_NAME||"rolax";let R=await fetch(c.url,{method:"POST",headers:f,body:JSON.stringify({model:c.model,messages:g,temperature:0.5})});if(!R.ok){let b=await R.text();throw Error(`LLM request failed (${R.status}): ${b}`)}return(await R.json())?.choices?.[0]?.message?.content?.trim()||""}async function n(c,g){console.log("* Explain your app idea as clearly as possible."),console.log("* When done type exit/quit/bye to end the chat!"),console.log(`Message: ${g}`);let f=[{role:"system",content:V.system},{role:"user",content:g}],R=Jc.createInterface({input:process.stdin,output:process.stdout});try{while(!0){let w=(await R.question("> ")).trim();if(!w)continue;if(/^(exit|quit|bye)$/i.test(w)){console.log("Exiting chat...");break}f.push({role:"user",content:w});let A=await k(c,f);if(A)console.log(A),f.push({role:"assistant",content:A})}}finally{R.close()}console.log("Generating final JSON summary...");let O={role:"user",content:"Return JSON only with keys 'agents' and 'todos'. Use concise markdown-ready text for each value."},j=(await k(c,[...f,O])).trim();console.log("Final response before parsing:",j);try{let w=j.indexOf("{"),A=j.lastIndexOf("}")+1;if(w>=0&&A>w)j=j.substring(w,A);return JSON.parse(j)}catch{return j}}var Yc=Uc();var zc=mc(process.cwd(),".env"),q=["OPENAI_API_KEY","OPENROUTER_API_KEY"],Wc=q.filter((c)=>!process.env[c]);P.default.config({path:zc});console.log("Rolax: Checking required environment variables...");if(Wc.length===q.length)console.error(`Error: At least one API key should be set: ${q.join(", ")}`),process.exit(1);console.log(`Detected platform: ${Yc}`);console.log("Environment variables loaded.");console.log("At least one API key is set.");async function Xc(){console.log("Starting Rolax...");let c=E[0],g=Object.values(i).find((R)=>R.name===c&&R.apiKey);if(!g)console.error("Error: No preferred LLM is configured with an API key."),process.exit(1);if(console.log("Preferred LLM:",g),await qc(g))console.log("App idea captured successfully.");else console.error("Failed to capture app idea.")}async function qc(c){let g=await n(c,"Hello, I would like to discuss my app idea.");if(g)console.log("Final JSON:",g),console.log("Agents.md-> ",g.agents);return g}Xc().catch((c)=>{console.error("Rolax failed:",c),process.exit(1)});
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -42,15 +42,23 @@ async function start() {
|
|
|
42
42
|
console.log("Preferred LLM:", preferredLLM)
|
|
43
43
|
|
|
44
44
|
// 1. Chat with user using the preferred LLM
|
|
45
|
-
await startChat(preferredLLM)
|
|
45
|
+
let appInfo = await startChat(preferredLLM)
|
|
46
|
+
|
|
47
|
+
// 2. Copy the template to the provided path and populate the AGENTS.md and TODOS.md files
|
|
48
|
+
if (appInfo) {
|
|
49
|
+
console.log("App idea captured successfully.")
|
|
50
|
+
} else {
|
|
51
|
+
console.error("Failed to capture app idea.")
|
|
52
|
+
}
|
|
46
53
|
}
|
|
47
54
|
|
|
48
|
-
async function startChat(llm: { name: string; apiKey: string; model: string, url: string }) {
|
|
55
|
+
async function startChat(llm: { name: string; apiKey: string; model: string, url: string }): Promise<{agents: string, todos: string} | undefined> {
|
|
49
56
|
let summary = await chatWithLLM(llm, "Hello, I would like to discuss my app idea.")
|
|
50
57
|
if (summary) {
|
|
51
58
|
console.log("Final JSON:", summary)
|
|
52
59
|
console.log("Agents.md-> ", summary.agents)
|
|
53
60
|
}
|
|
61
|
+
return summary
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
start().catch((error) => {
|
package/src/llm.ts
CHANGED
|
@@ -31,14 +31,14 @@ async function callChatCompletion(llm: { name: string; apiKey: string; model: st
|
|
|
31
31
|
})
|
|
32
32
|
|
|
33
33
|
if (!response.ok) {
|
|
34
|
-
|
|
34
|
+
let errorText = await response.text()
|
|
35
35
|
throw new Error(`LLM request failed (${response.status}): ${errorText}`)
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
type ChatCompletionResponse = {
|
|
39
39
|
choices?: Array<{ message?: { content?: string } }>;
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
let data = await response.json() as ChatCompletionResponse
|
|
42
42
|
return data?.choices?.[0]?.message?.content?.trim() || ""
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -47,19 +47,19 @@ export async function chatWithLLM(llm: { name: string; apiKey: string; model: st
|
|
|
47
47
|
console.log("* When done type exit/quit/bye to end the chat!")
|
|
48
48
|
console.log(`Message: ${message}`)
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
let messages: ChatMessage[] = [
|
|
51
51
|
{ role: "system", content: APP_BUILDER_PROMPTS.system },
|
|
52
52
|
{ role: "user", content: message },
|
|
53
53
|
]
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
let rl = readline.createInterface({
|
|
56
56
|
input: process.stdin,
|
|
57
57
|
output: process.stdout,
|
|
58
58
|
})
|
|
59
59
|
|
|
60
60
|
try {
|
|
61
61
|
while (true) {
|
|
62
|
-
|
|
62
|
+
let input = (await rl.question("> ")).trim()
|
|
63
63
|
if (!input) {
|
|
64
64
|
continue
|
|
65
65
|
}
|
package/src/prompts.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
export const APP_BUILDER_PROMPTS = {
|
|
4
4
|
system: `You are an expert app development assistant.
|
|
5
|
-
Your task is to interview users and get the basic idea about the app
|
|
5
|
+
Your task is to interview users and get the basic idea about the app.
|
|
6
6
|
Intension is to gather AGENTS.md and TODOS.md required to build the app.
|
|
7
7
|
Ask relevant questions to understand the app idea clearly.
|
|
8
8
|
Once you have enough information, generate AGENTS.md and TODOS.md files.
|