hello world

This commit is contained in:
raidendotai
2024-09-19 01:30:28 +01:00
commit a906249f7b
293 changed files with 20319 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

149
README.md Normal file
View File

@@ -0,0 +1,149 @@
[img]
# cofounder : early alpha release
* project - [cofounder.openinterface.ai](https://cofounder.openinterface.ai)
* 👋 [@n_raidenai](https://x.com/n_raidenai)
**cofounder**
- full stack generative web apps ; backend + db + stateful web apps
- gen ui rooted in app architecture, with ai-guided mockup designer & modular design systems
[demo]
---
## Important
**Early alpha release ; earlier than expected by 5/6 weeks**
Still not merged with key target features of the project, notably :
- project iteration modules for all dimensions of generated projects
- admin interface for event streams and (deeper) project iterations
- integrate the full genUI plugin :
* generative design systems
* deploy finetuned models & serve from api.cofounder
- local, browser-based dev env for the entire project scope
- add { react-native , flutter , other web frameworks }
- validations & swarm code review and autofix
- code optimization
- [...]
Be patient :)
---
# Usage
## Install & Init
* Open your terminal and run
```sh
npx @openinterface/cofounder -p "YourAppProjectName" -d "describe your app here" -a "(optional) design instructions"
```
Follow the instructions. The installer
- will ask you for your keys
- setup dirs & start installs
- will start the local `cofounder/api` builder and server
- will start generating your app 🎉
```
note :
you will be asked for a cofounder.openinterface.ai key
it is recommended to use one as it enables the designer/layoutv1 and swarm/external-apis features
and can be used without limits during the current early alpha period
the full index will be available for local download on v1 release
```
## Run
Your backend & vite+react web app will incrementally generate inside `./apps/{YourApp}`
Open your terminal in `./apps/{YourApp}` and run
```sh
npm i && npm run dev
```
It will start both the backend and vite+react, concurrently, after installing their dependencies
Go to `http://localhost:5173/` to open the web app 🎉
## Notes
### Local API
If you resume later and would like to iterate on your generated apps,
the local `./cofounder/api` server needs to be running to receive queries
You can (re)start the `local cofounder API` running the following command from `./cofounder/api`
```sh
npm run start
```
You can also generate new apps from the same env by running, from `./cofounder/api`, one of these command
```sh
npm run start -- -p "ProjectName" -f "some app description" -a "minimalist and spacious , light theme"
npm run start -- -p "ProjectName" -f "./example_description.txt" -a "minimalist and spacious , light theme"
```
### Concurrency
**[the architecture will be further detailed and documented later]**
Every "node" in the `cofounder` architecture has a defined configuration under `./cofounder/api/system/structure/nodes/{category}/{name}.yaml` to handle things like concurrency, retries and limits per time interval
For example, if you want multiple LLM generations to run in parallel (when possible - sequences and parallels are defined in DAGS under `./cofounder/api/system/structure/sequences/{definition}.yaml` ),
go to
```yaml
#./cofounder/api/system/structure/nodes/op/llm.yaml
nodes:
op:LLM::GEN:
desc: "..."
in: [model, messages, preparser, parser, query, stream]
out: [generated, usage]
queue:
concurrency: 1 # <------------------------------- here
op:LLM::VECTORIZE:
desc: "{texts} -> {vectors}"
in: [texts]
out: [vectors, usage]
mapreduce: true
op:LLM::VECTORIZE:CHUNK:
desc: "{texts} -> {vectors}"
in: [texts]
out: [vectors, usage]
queue:
concurrency: 50
```
and change the `op:LLM::GEN` parameter `concurrency` to a higher value
The default LLM concurrency is set to `1` so you can see what's happening in your console streams step by step - but you can increment it to `5`-`8`
---
# Docs, Design Systems, ...
**[WIP]**
---
# Architecture
[img]
---
# Some Credits
- Cover art edited from image found in [patriciaklein.de](https://patriciaklein.de)
- Demo design systems built using Figma renders / UI kits from:
* blocks.pm by Hexa Plugin (see `cofounder/api/system/presets`)
* google material
* figma core
* shadcn

49
TODO.md Normal file
View File

@@ -0,0 +1,49 @@
A non-ordered roadmap & todo dump
will update with proper map later, ignore for now
---
## nearest
merge with browser-based local dev env using webcontainers ; console.cofounder.openinterface.ai
## validation, errorfix
post-generation validation swarm modules
swarm autofix modules, merge
babel parse
## build, deploy
vite plugin to generate web app without the cofounder modules
generate packed projects ready for deployment
automate deployments, integrate different services
## design, layouts
plug in advanced designer + models
document how to custom design systems
add & index docs for shiny design systems
fonts / css modules
release extensive cofounder index on api access for layout designer to use
separate {desktop,mobile} in designer
RAG on icons via {text/clip} (like in openv0), maybe as a vite plugin
## functional
deploy latest index checkpoint in api.cofounder
## mgmt
more iteration modules, sequences to handle full lifecycle of generated projects
document everything
## platforms
react-native / flutter
more frontend frameworks
## project
technical articles
model train & serve from api
admin panel à la coolify
## also
SEO stuff
analytics into the dev feedback
animation (ie. framer-motion)
functional, api, python support api-side
benchmarks

8
apps/README.md Normal file
View File

@@ -0,0 +1,8 @@
## How to start apps
Your backend & vite+react web app will incrementally generate inside `./apps/{YourApp}`
Open your terminal in `./apps/{YourApp}` and run
```sh
npm i && npm run dev
```

34
cofounder/api/.env Normal file
View File

@@ -0,0 +1,34 @@
PORT = 667
OPENAI_API_KEY = "REPLACE_WITH_OPENAI_KEY"
ANTHROPIC_API_KEY = "REPLACE_WITH_ANTHROPIC_KEY"
COFOUNDER_API_KEY = "REPLACE_WITH_COFOUNDER.OPENINTERFACE.AI_KEY"
# llm, can be 'ANTHROPIC' (for claude sonnet 3.5) or 'OPENAI' (uses diff. models for diff. passes)
# make sure there are matching api keys
LLM_PROVIDER = "ANTHROPIC" #"OPENAI"
# should be kept to "text-embedding-3-small" to work with RAG using api.cofounder.openinterface.ai
EMBEDDING_MODEL = "text-embedding-3-small"
# RAG from index (from api.cofounder.openinterface.ai )
# enables features from { designer, swarm{externalapis} , ... }
# recommended to keep ; after alpha , in v1 release , big index will be release & downloadable to local
RAG_REMOTE_ENABLE = TRUE
STATE_LOCAL = TRUE # persist locally
AUTOEXPORT_ENABLE = TRUE # writes generated app files on each increment ; keep , necessary now
AUTOINSTALL_ENABLE = TRUE # runs "npm i" on exported projects whenever dependencies from generated code change
EXPORT_APPS_ROOT = "../../apps"
# these triggers the design system guided designer, generates a mockup layout image before implementing code
DESIGNER_ENABLE = TRUE
DESIGNER_DESIGN_SYSTEM = "presets/shadcn" #"presets/shadcn"
# enables : code review after code generated , augment features like searching for external apis to implement in server , ...
SWARM_ENABLE = TRUE
#STATE_CLOUD = TRUE # persist on cloud (firebase + cloudstorage)
#FIREBASE_SERVICE_KEY_PATH = "./firebase-service-key-p0dev.json"
#GOOGLECLOUDSTORAGE_SERVICE_KEY_PATH = "openv0-aa83086a03e1.json"
#GOOGLECLOUDSTORAGE_BUCKET = "uiray"

3
cofounder/api/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules/
db/
dump/

View File

@@ -0,0 +1,3 @@
db/
dump/
node_modules/

View File

@@ -0,0 +1,4 @@
{
"tabWidth": 1,
"useTabs": true
}

0
cofounder/api/README.md Normal file
View File

348
cofounder/api/build.js Normal file
View File

@@ -0,0 +1,348 @@
import fs from "fs";
import path from "path";
import yaml from "yaml-js";
import yml from "yaml";
import { merge, fromPairs } from "lodash-es";
import retry from "async-retry";
import pqueue from "p-queue";
import { EventEmitter } from "node:events";
import { promisify } from "util";
import { readdir } from "fs";
import delay from "delay";
const functionsDir = `./system/functions`;
const unitsDir = `./system/structure`;
const LOGS_ENABLED = true;
async function build({ system }) {
console.dir({ build: system.functions });
if (!system.nodes) system.nodes = {};
if (!system.functions) system.functions = {};
if (!system.sequences) system.sequences = {};
const queues = {};
const events = {
main: new EventEmitter(),
log: {
node: new EventEmitter(),
sequence: new EventEmitter(),
},
};
if (LOGS_ENABLED) {
events.log.node.on(`enqueue`, ({ id, context, data }) => {
console.log(
`\x1b[36mlog:enqueue: node:${id}\t${JSON.stringify({ context, data }).slice(0, 150)}\x1b[0m`,
);
});
events.log.node.on(`start`, ({ id, context, data }) => {
console.log(
`\x1b[33mlog:start: node:${id}\t${JSON.stringify({ context, data }).slice(0, 150)}\x1b[0m`,
);
});
events.log.node.on(`end`, ({ id, context, data, response }) => {
console.log(
`\x1b[32mlog:complete: node:${id}\t${JSON.stringify({ context, response, data }).slice(0, 150)}\x1b[0m`,
);
});
}
system.run = async ({ id, context, data }) => {
// console.dir({ __debug__system__run : { input : { id, context, data }, system_nodes: system.nodes, } })
try {
return await system.nodes[id].run({ context, data });
} catch (err) {
console.dir({ SYSTEM_RUN_ERR: { err, id } });
}
};
events.main.on(`run`, async ({ id, context, data }) => {
if (LOGS_ENABLED) {
console.log(`\x1b[31mevent:\`run\` →id:${id}\x1b[0m`);
}
await system.run({ id, context, data });
});
system.nodes = fromPairs(
await Promise.all(
Object.keys(system.functions)
.filter((id) => Object.keys(system.nodes).includes(id))
.map(async (id) => {
queues[id] = new pqueue({
concurrency: parseInt(system.nodes[id].queue?.concurrency) || Infinity,
intervalCap:
parseInt(system.nodes[id].queue?.interval?.limit) || Infinity,
interval: parseInt(system.nodes[id].queue?.interval?.time) || 0,
timeout: parseInt(system.nodes[id].queue?.timeout) || undefined,
});
// this is the function to be ran
const fn = async ({ context = {}, data = {} }) => {
events.log.node.emit(`enqueue`, { id, context, data });
return await queues[id].add(async () => {
events.log.node.emit(`start`, { id, context, data });
const response = await retry(
async (bail) => {
try {
const fnresponse = await system.functions[id]({
context: { ...context, run: system.run },
data: system.nodes[id].in?.length
? system.nodes[id].in.reduce(
(acc, inp) => ({ ...acc, [inp]: data[inp] || null }),
{},
) // higher perf than fromPairs ?
: data,
});
return !fnresponse
? { success: false }
: system.nodes[id].out?.length
? system.nodes[id].out.reduce(
(acc, inp) => ({ ...acc, [inp]: fnresponse[inp] || null }),
{},
)
: fnresponse;
} catch (error) {
console.dir({ asyncretry_error: { id, error } }, { depth: null });
throw new Error(error);
}
},
{
retries: parseInt(system.nodes[id].queue?.retry) || 5,
},
);
events.log.node.emit(`end`, { id, context, data, response });
return response;
});
};
return [
id,
{
type: `node`,
meta: system.nodes[id],
run: fn,
}, // to have same format as sequence : system.sequences[id].run and system.functions[id].run
];
}),
),
);
/*
make the DAG graph decomposition parallelizor from the system and relations
handle : seq , parallel , recursion too !
*/
/*
event registration for system triggers (nodes are all registered for events node:{id} )
*/
if (LOGS_ENABLED) {
events.log.sequence.on(`sequence:start`, ({ id, context, data }) => {
console.log(
`\x1b[34mlog:start: sequence:${id}\t${JSON.stringify({ context, data }).slice(0, 150)}\x1b[0m`,
);
});
events.log.sequence.on(
`sequence:step:start`,
({ id, index, over, context, data }) => {
console.log(
`\x1b[34mlog:start: sequence:${id}:step:${index}/${over - 1}\t${JSON.stringify({ context, data }).slice(0, 150)}\x1b[0m`,
);
},
);
events.log.sequence.on(
`sequence:step:end`,
({ id, index, over, context, data }) => {
console.log(
`\x1b[35mlog:done: sequence:${id}:step:${index}/${over - 1}\t${JSON.stringify({ context, data }).slice(0, 150)}\x1b[0m`,
);
},
);
events.log.sequence.on(`sequence:end`, ({ id, context, data }) => {
console.log(
`\x1b[35mlog:done: sequence:${id}\t${JSON.stringify({ context, data }).slice(0, 150)}\x1b[0m`,
);
});
}
async function makeDags() {
// need to implement recursion cases next !
return fromPairs(
Object.keys(system.sequences).map((sequenceId) => {
const inDegree = {},
adjList = {};
const seq = system.sequences[sequenceId];
const dag = fromPairs(
system.sequences[sequenceId].nodes.map((nodeId) => {
return [
nodeId,
{
parents: !seq.relations?.parents
? []
: !seq.relations?.parents[nodeId]?.length
? []
: seq.relations.parents[nodeId],
},
];
}),
);
Object.keys(dag).forEach((node) => {
inDegree[node] = 0;
adjList[node] = [];
});
Object.entries(dag).forEach(([node, { parents }]) => {
if (parents) {
parents.forEach((parent) => {
if (!adjList[parent]) {
console.error(
`build:DAG : parent node ${parent} of node ${node} not found in DAG - skipping dependency`,
);
} else {
adjList[parent].push(node);
inDegree[node]++;
}
});
}
});
const queue = Object.keys(inDegree).filter((node) => inDegree[node] === 0);
const sequence = [],
visitedNodes = new Set();
while (queue.length) {
const currentLevel = queue.splice(0, queue.length);
currentLevel.forEach((node) => {
visitedNodes.add(node);
adjList[node].forEach((neighbor) => {
if (--inDegree[neighbor] === 0) queue.push(neighbor);
});
});
sequence.push(currentLevel);
}
if (visitedNodes.size !== Object.keys(dag).length) {
console.dir({ dag, visitedNodes }, { depth: null });
throw new Error("The provided DAG has cycles or unresolved dependencies");
}
// later ; update for logging etc
const run = async ({ context, data }) => {
events.log.sequence.emit(`sequence:start`, {
id: sequenceId,
context,
data,
});
const sequenceLength = sequence.length;
for (const s of sequence.entries()) {
const [index, step] = s;
events.log.sequence.emit(`sequence:step:start`, {
id: sequenceId,
index,
over: sequenceLength,
context,
data,
});
await Promise.all(
step.map(async (parallelfnId) => {
const response = await system.run({
id: parallelfnId,
context: { ...context, run: system.run },
data,
});
data = merge(data, response);
}),
);
events.log.sequence.emit(`sequence:step:end`, {
id: sequenceId,
index,
over: sequenceLength,
context,
data,
});
}
events.log.sequence.emit(`sequence:end`, {
id: sequenceId,
context,
data,
});
return data;
};
if (system.sequences[sequenceId].triggers?.length) {
system.sequences[sequenceId].triggers.map((triggerevent) => {
events.main.on(triggerevent, async ({ context, data }) => {
if (LOGS_ENABLED) {
console.log(
`\x1b[31mevent:\`${triggerevent}\` →sequence:${sequenceId}\x1b[0m`,
);
}
await run({ context, data });
});
});
}
return [
sequenceId,
{
type: `sequence`,
meta: {
...system.sequences[sequenceId],
dag: sequence,
},
run,
},
];
}),
);
}
system.nodes = {
...system.nodes,
...(await makeDags()),
};
system.queues = queues;
system.events = {
events,
new: async ({ event, context = {}, data = {} }) => {
events.main.emit(event, { context, data });
}, // trigger events
run: async ({ id = false, context = {}, data = {} }) => {
events.main.emit(`run`, { id, context, data });
}, // run node/seq events
};
return system;
}
const readdirAsync = promisify(readdir);
async function getFilesRecursively(dir, ext) {
let results = [];
const list = await readdirAsync(dir, { withFileTypes: true });
for (const file of list) {
const filePath = path.join(dir, file.name);
if (file.isDirectory()) {
results = results.concat(await getFilesRecursively(filePath, ext));
} else if (file.name.endsWith(ext)) {
results.push(filePath);
}
}
return results;
}
const system = await build({
system: {
functions: merge(
{},
...(await Promise.all(
(await getFilesRecursively(functionsDir, ".js")).map((file) =>
import(`./${file}`).then((m) => m.default),
),
)),
),
...merge(
{},
...(await Promise.all(
(await getFilesRecursively(unitsDir, ".yaml")).map((file) =>
yaml.load(fs.readFileSync(`./${file}`, `utf-8`).toString()),
),
)),
),
},
});
export default {
system,
};

View File

@@ -0,0 +1,42 @@
{
"type": "module",
"aliases": {
"@": "."
},
"scripts": {
"start": "node --loader esm-module-alias/loader --no-warnings server",
"start:npx": "npm i && node --loader esm-module-alias/loader --no-warnings server",
"dev:build": "node --loader esm-module-alias/loader --no-warnings build"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.27.3",
"@google-cloud/storage": "^7.12.1",
"@resvg/resvg-js": "^2.6.2",
"async-retry": "^1.3.3",
"cloudconvert": "^2.3.7",
"colormap": "^2.3.2",
"cors": "^2.8.5",
"deepmerge": "^4.3.1",
"delay": "^6.0.0",
"dotenv": "^16.4.5",
"esm-module-alias": "^2.2.0",
"express": "^4.19.2",
"firebase-admin": "^12.4.0",
"firestore": "^1.1.6",
"fs-extra": "^11.2.0",
"js-yaml": "^4.1.0",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"module-alias": "^2.2.3",
"openai": "^4.55.4",
"p-all": "^5.0.0",
"p-queue": "^8.0.1",
"sharp": "^0.33.4",
"slugify": "^1.6.6",
"vectra": "^0.9.0",
"xml2js": "^0.6.2",
"yaml": "^2.5.0",
"yaml-js": "^0.3.1",
"yargs": "^17.7.2"
}
}

338
cofounder/api/server.js Normal file
View File

@@ -0,0 +1,338 @@
import express from "express";
import cors from "cors";
import dotenv from "dotenv";
import yargs from "yargs";
import fs from "fs";
import { hideBin } from "yargs/helpers";
import { merge } from "lodash-es";
import cofounder from "./build.js";
dotenv.config();
function _slugify(text) {
return text
.toString()
.toLowerCase()
.replace(/\s+/g, "-") // Replace spaces with -
.replace(/[^\w\-]+/g, "") // Remove all non-word chars
.replace(/\-\-+/g, "-") // Replace multiple - with single -
.replace(/^-+/, "") // Trim - from start
.replace(/-+$/, ""); // Trim - from end
}
// init project from argv
// to be called like : npm run start -- --p "some-project-name" --d "app description right"
const timestamp = Date.now();
const argv = yargs(hideBin(process.argv)).argv;
const newProject = {
project:
(!argv.p && !argv.project) ||
_slugify(argv.p || argv.project).length === 0 ||
!_slugify(argv.p || argv.project).match(/[a-z0-9]/)
? `project-${timestamp}`
: _slugify(argv.p || argv.project),
description: argv.description || argv.d || argv.desc || false,
aesthetics: argv.aesthetics || argv.a || argv.aesthetic || false,
};
if (argv.file || argv.f) {
newProject.description = fs.readFileSync(argv.file || argv.f, "utf-8");
}
async function createNewProject() {
if (!newProject.description.length) {
console.error(
'Error: -d "project description" is required and cannot be empty.',
);
process.exit(1);
}
console.log(
`\x1b[31minitialized generating app : ${newProject.project}\x1b[0m`,
);
console.log(
`\x1b[34m(see ${process.env.EXPORT_APPS_ROOT}/${newProject.project}/README.md for more details)\x1b[0m` +
`\n\x1b[38;5;37mto start app (api+frontend in parallel)` +
`\n\t> cd ${process.env.EXPORT_APPS_ROOT}/${newProject.project}` +
`\n\t> npm i && npm run dev\x1b[0m`,
);
const query = {
pm: {
details: {
text: `${newProject.project != `project-${timestamp}` ? "Project '" + newProject.project + "' :" : ""} ${newProject.description}`,
attachments: [],
design: {
aesthetics: {
text: newProject.aesthetics,
},
},
},
},
};
console.dir({ query }, { depth: null });
/*
// debug : to resume ----------------------------------------------------------
const data = await cofounder.system.run({
id: "op:PROJECT::STATE:LOAD",
context: {
project: newProject.project,
},
data: {},
});
await cofounder.system.run({
id: `seq:project:init:v1:resume`,
context: {
project: newProject.project,
},
data: merge(data, {
...query,
debug: {},
}),
});
----------------------------------------------------------
*/
await cofounder.system.run({
id: `seq:project:init:v1`,
context: {
project: newProject.project,
},
data: query,
});
}
// Call createNewProject if command args for init project are provided
if (newProject.project && newProject.description) {
createNewProject();
}
const app = express();
const PORT = process.env.PORT || 667;
app.use(cors());
app.use(express.json({ limit: "5mb" }));
/*
app.post("/project/init", async (req, res) => {
try {
// see docs for steps
res.status(200).json({ end: true });
} catch (error) {
console.error(error);
res.status(500).json({ error: "failed to init project" });
}
});
*/
const actions = {
// map action to function ; load means load project state before passing
"update:settings:preferences:versions": {
fn: _updateProjectPreferences,
load: false,
},
"regenerate:ui": { fn: _regenerateUiComponent, load: true },
"iterate:ui": { fn: _iterateUiComponent, load: true },
/*
later, single universal interface approach,
> should go through an analysis sequence ;
ie. is is a new feature that needs db schemas & apis to be altered, or just at the layout level, etc
*/
};
const actionsKeys = Object.keys(actions);
app.post("/project/actions", async (req, res) => {
/*
in : {
project : `exampleproject`,
query : {
action : "example:action:whatever",
data : {
},
},
}
*/
console.dir(
{ "cofounder:api:server:actions:debug": req.body },
{ depth: null },
);
try {
const { project, query } = req.body;
const { action } = query;
if (!actionsKeys.includes(action)) {
throw new Error(`action ${action} not recognized`);
}
const { fn, load } = actions[action];
const data = await fn({
request: { project, query },
data: !load
? {}
: await cofounder.system.run({
id: "op:PROJECT::STATE:LOAD",
context: {
project,
},
data: {},
}),
});
res.status(200).json({ end: true });
} catch (error) {
console.error(error);
res.status(500).json({ error: "failed to process" });
}
});
app.listen(PORT, () => {
console.log(
"\x1b[32m\ncofounder/api : server is running on port " + PORT + "\x1b[0m",
);
});
// ------------ helpers --------------------------------------------------------
async function _updateProjectPreferences({ request }) {
/*
in : {
project : `exampleproject`,
query : {
action : "example:action:whatever",
data : {
[views || sections] : {
[id] : {version}
}
},
},
}
*/
const { project, query } = request;
await cofounder.system.run({
id: "op:PROJECT::STATE:UPDATE",
context: { project },
data: {
operation: {
id: `settings:preferences:versions`,
},
type: `end`,
content: {
key: `settings.preferences.versions`,
data: query.data,
},
},
});
}
async function _regenerateUiComponent({ request, data }) {
const { project, query } = request;
/*
in : request: {
project : `exampleproject`,
query : {
action : "regenerate:ui"
data : {
[views || sections] : `{id}`, // <--- update : sections stuff removed, is views only (for now)
},
},
}
*/
const type = Object.keys(query.data)[0];
const id = query.data[type];
/*
need to make :
task {
type: "view",
view: {
type: unique || shared,
id,
},
passes: {
functional: true,
redesign: process.env.DESIGNER_ENABLE
? JSON.parse(process.env.DESIGNER_ENABLE.toLowerCase())
: true,
}
}
*/
const task = {
type: "view",
view: {
type: id.startsWith(`UV_`) ? `unique` : `shared`,
id,
},
passes: {
functional: true,
redesign: process.env.DESIGNER_ENABLE
? JSON.parse(process.env.DESIGNER_ENABLE.toLowerCase())
: false,
},
};
console.dir({ "debug:server:task:regen:ui": { request, task } });
await cofounder.system.run({
id: "WEBAPP:VIEW::GENERATE",
context: { project },
data: {
...data,
task,
},
});
}
async function _iterateUiComponent({ request, data }) {
console.dir({ "cofounder:api:server:iterate:ui": "starts" });
/*
designer/layoutv1 might be overkill, but its best way to have primitives to retrieve design system docs (if applies)
*/
/*
in : {
project: meta.project,
query: {
action: "iterate:ui",
data: {
views : {
[id] : {
[version] : {
user : {
text: editUserText,
attachments: [], // later, can attach image
},
screenshot: { base64: image ? image : false},
designer: bool
}
},
}
},
},
}),
}
*/
const { project, query } = request;
const id = Object.keys(query.data.views)[0];
const version = Object.keys(query.data.views[id])[0];
const { notes, screenshot, designer } = query.data.views[id][version];
const task = {
type: "view",
view: {
type: id.startsWith(`UV_`) ? `unique` : `shared`,
id,
version,
},
iteration: {
notes, // {text,attachements}
screenshot, // {base64 : "base64str" || false }
designer: process.env.DESIGNER_ENABLE
? JSON.parse(process.env.DESIGNER_ENABLE.toLowerCase()) && designer
? true
: false
: false,
},
};
console.dir({ "debug:server:task:regen:ui": { request, task } });
await cofounder.system.run({
id: "WEBAPP:VIEW::ITERATE",
context: { project },
data: {
...data,
task,
},
});
}

View File

@@ -0,0 +1,171 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function backendAsyncapiDefine({ context, data }) {
if (!data.backend.requirements?.realtimeWebsockets?.required) {
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "backend:specifications:asyncapi",
},
type: `end`,
content: {
key: "backend.specifications.asyncapi",
data: {},
},
},
});
return {
backend: {
specifications: {
asyncapi: {},
},
},
};
}
const { pm, db, backend } = data;
const { prd, frd, drd, brd } = pm;
const messages = [
{
role: "system",
content: `- you are a genius Product Manager & Software Architect & Backend designer
- your role is to make the backend asyncAPI specs for the realtime features of the provided task
- your asyncAPI specs should be comprehensive, and include schema object for each case,
which will be used as references to build the frontend app connected to the backend
- cover all cases ; data-related tasks only (ie. you are making a mock backend for user-facing data operations)
- do a thorough analysis of the provided task
- think from perspectives of multiple personas, put yourself in situation, to make sure your asyncAPI definition is fully comprehensive and ready to be used in production exactly as is
- ask yourself:
* what are all the events & schemas required by features expected to be seen by users in the frontend ?
- ask yourself:
* what are all the events & schemas required by features expected to be seen by users in the app ?
- your aim is to cover all realtime use cases, as the expert product manager & architect you are
---
the root dev url for the server is "http://localhost:1337" ; you can specify that in specs
---
give a final, super comprehensive answer in strict, parseable asyncAPI YAML format
which will be perfectly ready to plug into the backend in development,
and pushed to staging directly and work flawlessly
it should be comprehensive for the needs required by all the realtime events described in the provided docs
answer in strict parseable asyncAPI in YAML format,
with all schemas, for all scenarios ; - and specifying cases when a given schema field is required
super important :
> methods, routes, operationIds, and components (parameters and components) only
> no input/output examples objects !
> you are only to detail realtime events and their schemas for realtime features described in the provided documents !
---
important :
use snake_case for any naming you do
---
your reply will be directly transferred as the final asyncAPI structure for the realtime events part of the backend,
so do not put anything else in your reply besides the asyncAPI structure that details the realtime events parts of the backend only !
your reply should start with : "\`\`\`yaml" and end with "\`\`\`"
you will be tipped $99999 + major company shares for nailing it perfectly off the bat`,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`DRD:database-requirements-document
${drd}
\`\`\`
---
\`\`\`DB:schemas
${yaml.stringify({ schemas: db.schemas })}
\`\`\`
`,
},
{
role: "user",
content: `\`\`\`BRD:Backend-requirements-document
${brd}
\`\`\``,
},
{
role: "user",
content: `implement the asyncAPI structure , for the realtime features specified in the provided documents
super important :
- your only focus is to make the asyncAPI for realtime events and their details , not anything else (such as a REST API ...)
- asyncAPI for realtime events and their details only !
it is expected to be very comprehensive and detailed ; in a VALID PARSEABLE YAML format
you're a genius`,
},
];
const asyncapiStructure = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages,
preparser: `backticks`,
parser: `yaml`,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "backend:specifications:asyncapi",
},
type: `end`,
content: {
key: "backend.specifications.asyncapi",
data: asyncapiStructure,
},
},
});
return {
backend: {
...data.backend,
specifications: {
asyncapi: asyncapiStructure,
},
},
};
}
export default {
"BACKEND:ASYNCAPI::DEFINE": backendAsyncapiDefine,
};

View File

@@ -0,0 +1,176 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function backendOpenapiDefine({ context, data }) {
if (!data.backend.requirements?.restApi?.required) {
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "backend:specifications:openapi",
},
type: `end`,
content: {
key: "backend.specifications.openapi",
data: {},
},
},
});
return {
backend: {
specifications: {
openapi: {},
},
},
};
}
const { pm, db, backend } = data;
const { prd, frd, drd, brd } = pm;
const messages = [
{
role: "system",
content: `- you are a genius Product Manager & Software Archtect & API designer
- your role is to make the openAPI specs for the user-facing API for the provided task
- your API should be comprehensive, and include schema object for each case,
which will be used as references to build the frontend app connected to the API
- cover all cases ; data-related tasks only (ie. you are making a mock api for user-facing data operations)
- do a thorough analysis of the provided task
- think from perspectives of multiple personas, put yourself in situation, to make sure your openAPI definition is fully comprehensive and ready to be used in production exactly as is
- ask yourself:
* what are the key personas using the user-facing, frontend API ?
* what are all the routes & schemas required by features expected to be seen by users in the frontend ?
* am i assigning an "operationId" for every path&route ?
- ask yourself:
* what are all the routes & schemas required by features expected to be seen by users in the app ?
- your answer will be pushed to production and will be responsible for an app used by thousands of users, instantly
- your aim is to cover all use cases, as the expert product manager & architect you are
---
give a final, super comprehensive answer in strict, parseable openAPI 3.0.0 YAML format
which will be perfectly ready to plug into the backend in development,
and pushed to staging directly and work flawlessly
it should be comprehensive for the needs required by all the features
answer in strict parseable openAPI 3.0.0 in YAML format,
with all schemas, for all scenarios ; - and specifying cases when a given schema field is required
the root dev url for the API is "http://localhost:1337" ; you can specify that in openapi
super important :
> methods, routes, operationIds, and components (parameters and components) only
> no input/output examples objects !
> include a "summary" key for each route
---
> note : if auth functionalities are present, use an architecture that will be compatible with a simple JWT auth system !
ie.
> \`Authorization: Bearer <token>\` in headers on authenticated requests
> jwt type methods that return the authorization token on login, and that is used in header by subsequent authenticated requests
important : if auth methods in api, token should be returned on both signup and login !
---
important :
use snake_case for any naming you do
---
your reply will be directly transferred as the final OPENAPI structure, so do not put anything else in your reply besides the openAPI structure
your reply should start with : "\`\`\`yaml" and end with "\`\`\`"
you will be tipped $99999 + major company shares for nailing it perfectly off the bat`,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`DRD:database-requirements-document
${drd}
\`\`\`
---
\`\`\`DB:schemas
${yaml.stringify({ schemas: db.schemas })}
\`\`\`
`,
},
{
role: "user",
content: `\`\`\`BRD:Backend-requirements-document
${brd}
\`\`\``,
},
{
role: "user",
content: `implement the openAPI structure
it is expected to be very comprehensive and detailed ; in a VALID PARSEABLE YAML format
you're a genius`,
},
];
const openapiStructure = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages,
preparser: `backticks`,
parser: `yaml`,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "backend:specifications:openapi",
},
type: `end`,
content: {
key: "backend.specifications.openapi",
data: openapiStructure,
},
},
});
return {
backend: {
...data.backend,
specifications: {
openapi: openapiStructure,
},
},
};
}
export default {
"BACKEND:OPENAPI::DEFINE": backendOpenapiDefine,
};

View File

@@ -0,0 +1,387 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function backendServerGenerate({ context, data }) {
/*
base on dev:test oneshot function
mix with the bak api generate for the make sure blabla
*/
const { pm, db, backend } = data;
const { prd, frd, drd, brd } = pm;
const { openapi, asyncapi } = backend.specifications;
const messages = [
{
role: `system`,
content: `Your task, as the genius backend dev expert you are, is to generate the full nodejs script for a module, based on the provided specifications and details of the backend in development
your role is to implement the full express server for the provided task for the \`server.mjs\` (type: module script)
you will answer in 3 parts :
- analysis , in between \`\`\`markdown\`\`\`\` section
- code , in between \`\`\`mjs\`\`\`\` section
- dependencies and env variables , in between \`\`\`yaml\`\`\`\` section ; where any needed packages to install and needed env variables to setup will be mentionned ; the yaml should have objects : { dependencies : {"package":"version"} , env : {"key" , "temp_value"} } ("dependencies" (for packages) and "env" for env variables (and their temporary values) )
use doublequotes for every string inside the yaml to make sure formatting is good
---
in your analysis, ask yourself :
- what features are expected ?
does it need DB operations ?
does it need storage ?
> if so , how to handle the file storage / uploads / serving locally ?
does it need realtime features and websocket events ?
what operations are expected from the server to perfectly meet what the user expects from the feature ?
think slowly, do not rush to answer ;
think : am i achieving great UX ? am i doing great, perfect work ?
do not overlook details !
in your code, include comment blocks before each implemented function or operation where you analyze what is done and why - it wil help you reason through more thoroughly and do a much greater work
> super important :
- in case a function requires the use of an external API (ie. for checking a stock price , or generating some image , ... ),
you should include the following decorator inside your pre-function comment :
\`@@need:external-api : description of the external api necessitated and what it should do\`
you should also return a mock response that fits the right schema requirements ! so that the server returns mock responses in worst case !
important : external APIs should only handle external functionalities like the ones mentionned ; the server already has storage and DB access, so those do not need external APIs !
important : no placeholders ! no replace later ! no hallucinated unfinished code ! return a mock response that fits schema requirements in case you need to !
if feature needs external api, include the specified decorator \`@@need:external-api : description...\` in comment and return a mock response instead !
---
for any db requirements, use postgres from \`@electric-sql/pglite\`
- to use postgres, include this snippet in your script :
\`\`\`
import { PGlite } from "@electric-sql/pglite";
const postgres = new PGlite("./db");
/* then, can be used like this :
await postgres.query("SELECT * FROM exampletable;")
*/
// note : the postgres tables + seed were already created before , you can use the postgres directly without configuring it
\`\`\`
postgres is use exactly how is provided in the snippet, do not change anything about loading it / configuring it, else it breaks ;
postgres is imported, initialized and queries EXACTLY AS SHOWN IN THE SNIPPET ! NO OTHER WAY !
---
notes :
- make sure cors is enabled
- if you need realtime, you can use socket.io
if you need file storage capabilities (ie. file upload/download features), you can write/read locally from the \`./storage\` folder (create it if needed)
for any db requirements, use postgres ; you can only use postgres (from @electric-sql/pglite ) with raw queries (no ORMs or anything)
- to use postgres, include this snippet in your script :
\`\`\`
import { PGlite } from "@electric-sql/pglite";
const postgres = new PGlite("./db");
/* then, can be used like this :
await postgres.query("SELECT * FROM exampletable;")
*/
\`\`\`
note : the postgres tables + seed were already created before , you can use the postgres directly without configuring it ; do not create tables in script !
extremely important :
- the DB R/W need to be 100% compatible with the tables and schemas of the provided DB specifications !!
- if auth needed, use jwt middleware
important : if auth , make sure you return token both on signup and login (even if openapi might have skipped that detail ! else stuff might break ! )
important : if auth , and also realtime websockets features , make sure auth / jwt also applies to sockets not just the api
- if some function is too complex too implement (ie. needs more than known packages or DB R/W operations or too complex etc ...), you should return a mock response ; most important is : do not leave some "placeholder" function of value , do the mockup work if needed !
everything needs to be implemented and working, no placeholders, no hallucinated imports, no "do this later" ; everything working perfect in one single script !
- if you need realtime, you can use socket.io
if you need file storage capabilities (ie. file upload/download features), you can write/read locally from the \`./storage\` folder (create it if needed)
for any db requirements, use postgres ; you can only use postgres (from @electric-sql/pglite ) with raw queries (no ORMs or anything)
- if auth needed, use jwt middleware
important : if auth , make sure you return token both on signup and login (even if openapi might have skipped that detail ! else stuff might break ! )
- use morgan middleware to log any incoming request and details (ie. method, path, headers, params, query, body) - just for better dev exp
- if it makes use of .env , make your you import \`dotenv\` and \`dotenv.config()\` to read .env before !
---
extremely important :
- get the server port from env ; make default PORT always 1337 !!
---
extremely important :
- you are to implement the entire server as specified in the provided docs , with a focus on DB R/W operations
- you are to implement every single thing needed by the backend server and output one single big working perfect \`server.mjs\` script
> if backend has REST API , everything required and mentionned in the openAPI specs
> if backend has realtime websockets , everything required and mentionned in the asyncAPI specs
> if backend has both REST API and realtime Websockets , everything required by both and everything mentionned in both openAPI specs and asyncAPI specs ; and both working perfectly within the same \`server.mjs\`
- do not assume anything is implemented yet ! you will do 100% of everything needed and output one single big working perfect \`server.mjs\` script
- no placeholders, no hallucinated imports
- again, do not assume anything is implemented yet ! you will do 100% of everything needed and output one single big working perfect \`server.mjs\` script
- again , you are to implement every single thing needed by the backend server:
> if backend has REST API , everything required and mentionned in the openAPI specs
> if backend has realtime websockets , everything required and mentionned in the asyncAPI specs
> if backend has both REST API and realtime Websockets , everything required by both and everything mentionned in both openAPI specs and asyncAPI specs ; and both working perfectly within the same \`server.mjs\`
> one single big working perfect \`server.mjs\` script
- if it makes use of .env , make your you import \`dotenv\` and \`dotenv.config()\` to read .env before !
---
important:
> if some mock data is meant to to store an image url, use a https://picsum.photos/ url with a random seed
---
important :
> use snake_case for any naming you do
> ensure full perfect coherence with DB fields names and provided specs names
---
extremely important :
- the DB R/W need to be 100% compatible with the tables and schemas of the provided DB specifications !!
---
extremely important :
- if you have to mock a function (ie. because it needs external APIs functionalities), make sure that:
> the endpoint / event still returns something that is fitting with the response schemas
> the endpoint / event triggers a function that you mock somewhere in the script and uses its response in the flow
> the mock function that needs to be augmented later is actually triggered by the endpoint / event that needs it !
and has the right response formats
> the mock function has instructions in surrounding comments on what the function needs to be updated !
so that once the function is updated, there are no subsequent updates to make, as it would already be plugged into the server flows and be consistent 100%
> example :
\`\`\`example-code-snippet
...
/*
@need:external-api: An example description of some external api feature
*/
async function example_function_to_mock_name({...}){
// returning a mock response in the expected response format for now
return {
timestamp: Date.now(),
example_field_in_expected_format_structure: {
id: 237,
dummy: "example dummy string",
someResults: ["whatever","dummy"],
avatar: "https://picsum.photos/id/237/200/300"
},
}
}
...
app.post('/api/example-complex-feature', async (req, res) => {
...
const fetched_data = await example_function_to_mock_name({ ... })
...
})
...
\`\`\`
- the app flow must still be 100% working perfect everywhere
you are a genius + you get tipped $9999999
`,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:features-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `
\`\`\`DB:postgres:sql
${db.postgres}
\`\`\`
---
extremely turbo important :
> pay extreme attention to DB details :
> the things that you are expected to provide with inserts :
> should you make a uuid before inserting with postgres query ?
> are there key constraints ?
> is the db querying code using the exact names as in db fields ?
> are you providing everything needed to db every single time ?
`,
},
{
role: "user",
content: `\`\`\`BRD:backend-requirements-document
${brd}
\`\`\``,
},
data.backend?.requirements?.restApi?.required && {
role: "user",
content: `\`\`\`BACKEND:specifications:openAPI
${yaml.stringify(openapi)}
\`\`\``,
},
data.backend?.requirements?.realtimeWebsockets?.required && {
role: "user",
content: `\`\`\`BACKEND:specifications:asyncAPI
${yaml.stringify(asyncapi)}
\`\`\``,
},
{
role: `user`,
content: `extremely important :
- you are to implement the entire \`server.mjs\` as specified in the backend specifications , with a focus on DB R/W operations
- you are to implement every single thing needed by the server and output one single big working perfect \`server.mjs\` script
- do not assume anything is implemented yet ! you will do 100% of everything needed and output one single big working perfect \`server.mjs\` script
- no placeholders, no hallucinated imports
---
extremely turbo important :
> pay extreme attention to DB details :
> the things that you are expected to provide with inserts :
> should you make a uuid before inserting with a postgres query ?
> are there key constraints ? should you create something before inserting something else because of contraints ?
> is the db querying code using the exact names as in db fields ?
> are you providing everything needed to db every single time ?
---
extremely important :
- get the server port from env ; make default PORT always 1337 !!
- if a function needs a external api to satisfy the expected feature, include the specified decorator \`@@need:external-api : description...\` in comment (in the code right before the concerned function) and return a mock response instead !
- note : the postgres tables + seed were already created before , you can use the postgres directly without configuring it ; do not create tables in script !
- if auth needed, use jwt middleware
> important : if auth , make sure you return token both on signup and login (even if openAPI might have skipped that detail ! else stuff might break ! )
> important : if auth , and also realtime websockets features , make sure auth / jwt also applies to sockets not just the api !
- again, do not assume anything is implemented yet ! you will do 100% of everything needed and output one single big working perfect \`server.mjs\` script
- again , you are to implement every single thing needed by the server and output one single big working perfect \`server.mjs\` script
- no placeholders, no hallucinated imports ; one 100% perfect complete working server script
extremely important :
- the DB R/W need to be 100% compatible with the tables and schemas of the provided DB specifications !!
now do the analysis , write the full working script and specify the dependencies+env`,
},
].filter((e) => e);
const { generated } = await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages: messages,
preparser: false,
parser: false,
},
});
const extraction = await utils.parsers.extract.backticksMultiple({
text: generated,
delimiters: [`markdown`, `mjs`, `yaml`],
});
const { mjs } = extraction;
if (!mjs.length || !extraction.yaml) {
throw new Error("backend:server:generate error - generated is empty");
}
const parsedYaml = extraction.yaml ? yaml.parse(extraction.yaml) : {};
let generatedServer = {
mjs,
dependencies: parsedYaml.dependencies
? Object.fromEntries(
Object.keys(parsedYaml.dependencies).map((key) => [key, "*"]),
)
: [],
env: parsedYaml.env ? parsedYaml.env : {},
timestamp: Date.now(),
};
// call swarm/agument:external-apis without waiting ; it will iterate it finds any external api decorators and replace
generatedServer = {
...generatedServer,
...(await context.run({
id: `SWARM:AUGMENT::BACKEND:EXTERNALAPIS`,
context,
data: {
...data,
task: {
code: generatedServer.mjs,
},
},
})), //-> {mjs,dependencies?,env,timestamp} ; will replace if new else returns empty object
};
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "backend:server:main",
},
type: `end`,
content: {
key: "backend.server.main",
data: generatedServer,
},
},
});
if (
Object.keys(generatedServer.dependencies).length ||
Object.keys(generatedServer.env).length
) {
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "settings:config:package",
},
type: `end`,
content: {
key: "settings.config.package",
data: {
backend: {
dependencies: generatedServer.dependencies,
env: generatedServer.env,
},
},
},
},
});
}
return {
backend: {
...data.backend,
server: {
main: generatedServer,
},
},
};
}
export default {
"BACKEND:SERVER::GENERATE": backendServerGenerate,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
import utils from "@/utils/index.js";
async function opConvertMarkdownPdf({ context, data }) {
/* ;; op:CONVERT::MARKDOWN:PDF
{markdown} -> {pdf {base64 , url(cloudstorage) } }
*/
return {};
}
export default {
"op:CONVERT::MARKDOWN:PDF": opConvertMarkdownPdf,
};

View File

@@ -0,0 +1,81 @@
import utils from "@/utils/index.js";
import axios from "axios";
import dotenv from "dotenv";
dotenv.config();
async function opIndexdbQuery({ context, data }) {
/* ;; op:INDEXDB::QUERY
query from vector db ; currently one local index, later more indices, from url
in: {text,vector,amount} // either text or vector
out: {results}
*/
/*
add .env RAG_REMOTE_ENABLE = TRUE
later retest for local, esp when empty
*/
const { index, text, vector, amount } = data;
let results = [];
if (
process.env.RAG_REMOTE_ENABLE &&
JSON.parse(process.env.RAG_REMOTE_ENABLE.toLowerCase()) &&
process.env.COFOUNDER_API_KEY?.length &&
process.env.COFOUNDER_API_KEY != "REPLACE_WITH_COFOUNDER.OPENINTERFACE.AI_KEY"
) {
try {
const response = await axios.post(
`https://api.openinterface.ai/cofounder/alpha/dev/rag/${index}`,
{
vector: vector
? vector
: (
await context.run({
id: `op:LLM::VECTORIZE`,
context,
data: {
texts: [text],
},
})
).vectors[0],
amount,
},
{
headers: {
Authorization: `Bearer ${process.env.COFOUNDER_API_KEY}`,
},
timeout: 30000, // 30 seconds timeout
},
);
return response.data;
} catch (error) {
console.error(error);
return { results: [] };
}
}
try {
// to avoid vectorizing for nothing
if (!utils.vectra.indexed) return { results: [] };
return {
results: await utils.vectra.query({
vector: vector
? vector
: (
await context.run({
id: `op:LLM::VECTORIZE`,
context,
data: {
texts: [text],
},
})
).vectors[0],
amount,
}),
};
} catch (e) {
false;
}
return { results: [] };
}
export default {
"op:INDEXDB::QUERY": opIndexdbQuery,
};

View File

@@ -0,0 +1,122 @@
import utils from "@/utils/index.js";
import dotenv from "dotenv";
dotenv.config();
async function opLlmGen({ context, data }) {
/* ;; op:LLM::GEN
{model,messages,preparser,parser,...} -> { response , tokens (consumption) }
in : ["model","messages","preparser","parser","query","stream"]
out : ["generated","usage"]
*/
/*
formats ;;
preparser : async ({text}) -> generated
parser : async ({generated,query})
*/
let { model, messages, preparser, parser, validate, query, stream } = data;
if (!stream) stream = process.stdout;
if (!preparser) {
preparser = async ({ text }) => {
return { text };
};
} else if (preparser === `backticks`) {
preparser = utils.parsers.extract.backticks; // most likely to be used
}
if (!parser) {
parser = async ({ generated, query }) => {
return generated.text;
};
} else if (parser === `yaml`) {
parser = utils.parsers.parse.yaml;
}
const llm_fn = !process.env.LLM_PROVIDER
? utils.openai.inference
: process.env.LLM_PROVIDER.toLowerCase() === "openai"
? utils.openai.inference
: utils.anthropic.inference;
const { text, usage } = await llm_fn({
model: model,
messages,
stream,
});
const generated_pre = await preparser({ text }); // -> typically { text : "... extracted text ..." }
const generated_post = await parser({
generated: generated_pre,
query,
});
if (validate) {
try {
await validate({ generated: generated_post });
} catch (e) {
console.dir({ "op:LLM::GEN error": e });
throw new Error(e);
}
}
return {
generated: generated_post,
usage,
};
}
function chunkify(array, chunkSize) {
const chunks = [];
for (let i = 0; i < array.length; i += chunkSize) {
chunks.push(array.slice(i, i + chunkSize));
}
return chunks;
}
async function opLlmVectorizeChunk({ context, data }) {
/* ;; op:LLM::VECTORIZE:CHUNK
{texts} -> {vectors,usage}
chunk processor (batches of 20)
queue concurrency/lims defined for this one
*/
const { texts } = data;
return await utils.openai.vectorize({
texts,
});
}
async function opLlmVectorize({ context, data }) {
/* ;; op:LLM::VECTORIZE
{texts} -> {vectors,usage}
chunkify, process, flatten, return
*/
const { texts } = data;
const chunks = chunkify(texts, 20);
let usageAll = { prompt_tokens: 0, total_tokens: 0 };
const vectorsAll = (
await Promise.all(
chunks.map(async (chunk) => {
const { vectors, usage } = await context.run({
id: `op:LLM::VECTORIZE:CHUNK`,
context,
data: { texts: chunk },
});
usageAll.prompt_tokens += usage.prompt_tokens;
usageAll.total_tokens += usage.total_tokens;
return vectors;
}),
)
).flat();
return {
vectors: vectorsAll,
usage: usageAll,
};
}
export default {
"op:LLM::GEN": opLlmGen,
"op:LLM::VECTORIZE": opLlmVectorize,
"op:LLM::VECTORIZE:CHUNK": opLlmVectorizeChunk,
};

View File

@@ -0,0 +1,739 @@
import utils from "@/utils/index.js";
import { sample, merge } from "lodash-es";
import path from "path";
import fs from "fs";
import yaml from "yaml";
import dotenv from "dotenv";
import fsextra from "fs-extra";
import { execSync } from "child_process";
dotenv.config();
/*
maps to local / hosted db paths
*/
const pm = {
"pm:details": "pm/user/details",
"pm:brd": "pm/docs/brd",
"pm:drd": "pm/docs/drd",
"pm:fjmd": "pm/docs/fjmd",
"pm:frd": "pm/docs/frd",
"pm:prd": "pm/docs/prd",
"pm:uxdmd": "pm/docs/uxdmd",
"pm:uxsmd": "pm/docs/uxsmd",
};
const architecture = {
"architecture:uxsitemap:structure": "architecture/uxsitemap/structure",
"architecture:uxdatamap:structure": "architecture/uxdatamap/structure",
"architecture:uxdatamap:views": "architecture/uxdatamap/views",
};
const backend = {
"backend:requirements": "backend/structure/requirements",
"backend:specifications:asyncapi": "backend/specifications/asyncapi",
"backend:specifications:openapi": "backend/specifications/openapi",
"backend:server:main": "backend/server/main",
};
const db = {
"db:schemas": "db/mock/schemas",
"db:seed": "db/mock/seed",
"db:postgres": "db/mock/postgres",
};
/*
const ui = {
"ui:layout:views": "ui/layout/mockup/views/{id}/versions/{version}",
"ui:layout:sections": "ui/layout/mockup/sections/{id}/versions/{version}",
//"ui:render:views" : "",
//"ui:render:sections": "",
"ui:code:react:stores": "ui/code/react/stores/{id}/versions/{version}",
"ui:code:react:root": "ui/code/react/root/{id}/versions/{version}",
"ui:code:react:views": "ui/code/react/views/{id}/versions/{version}",
"ui:code:react:sections": "ui/code/react/sections/{id}/versions/{version}",
};
*/
const webapp = {
"webapp:react:store": "webapp/code/react/store/{id}/versions/{version}",
"webapp:react:root": "webapp/code/react/root/{id}/versions/{version}",
"webapp:react:views": "webapp/code/react/views/{id}/versions/{version}",
"webapp:layout:views": "webapp/design/layout/views/{id}/versions/{version}",
};
const settings = {
// for version control ie. which view / section / version
// data is ie. {views{[id]:[version]}}
"settings:preferences:versions": "settings/preferences/versions",
"settings:config:package": "settings/config/package",
};
const modules = {
...pm,
...architecture,
...db,
...backend,
...webapp,
//...ui,
...settings,
};
const config = {
merge: [
// operation ids where merge data is enabled
"settings:preferences:versions",
"settings:config:package",
],
exports: [
// events that trigger app write exports (if enabled)
"db:postgres",
"backend:specifications:asyncapi",
"backend:specifications:openapi",
"backend:server:main",
"webapp:react:store",
"webapp:react:root",
"webapp:react:views",
"webapp:layout:views",
/*
"ui:layout:views",
"ui:layout:sections",
"ui:code:react:stores",
"ui:code:react:root",
"ui:code:react:views",
"ui:code:react:sections",
*/
"settings:preferences:versions",
"settings:config:package",
],
};
async function _exportOnSave({ context, data }) {
if (
!(
process.env.AUTOEXPORT_ENABLE &&
JSON.parse(process.env.AUTOEXPORT_ENABLE.toLowerCase())
)
)
return;
const { project } = context;
const { id, refs } = data.operation;
const root = `${process.env.EXPORT_APPS_ROOT}/${project}`;
const backendRoot = `${root}/backend`;
const appRoot = `${root}/vitereact`;
const appSrcRoot = `${appRoot}/src`;
// const { data } = data.content.data
let tasks = [];
if (id === `backend:server:main`) {
const { mjs, dependencies, env } = data.content.data;
tasks.push({
path: `${backendRoot}/server.js`,
data: mjs,
});
}
if (id === `backend:specifications:asyncapi`) {
if (data.content.data) {
const exportPath = `${backendRoot}/asyncapi.yaml`;
const exportData = yaml.stringify(data.content.data);
tasks.push({
path: exportPath,
data: exportData,
});
}
}
if (id === `backend:specifications:openapi`) {
if (data.content.data) {
const exportPath = `${backendRoot}/openapi.yaml`;
const exportData = yaml.stringify(data.content.data);
tasks.push({
path: exportPath,
data: exportData,
});
}
}
if (id === `db:postgres`) {
const exportPath = `${backendRoot}/db.sql`;
const exportData = data.content.data;
tasks.push({
path: exportPath,
data: exportData,
});
}
if (id === `webapp:react:store`) {
const exportPath = `${appSrcRoot}/store/main.tsx`;
const exportData = data.content.data.tsx;
tasks.push({
path: exportPath,
data: exportData,
});
}
if (id === `webapp:react:root`) {
const exportPath = `${appSrcRoot}/App.tsx`;
const exportData = data.content.data.tsx;
tasks.push({
path: exportPath,
data: exportData,
});
// just in case it wasnt setup properly, lets write meta.json here too
tasks.push({
path: `${appSrcRoot}/_cofounder/meta.json`,
data: JSON.stringify({ project }),
});
}
if (id === `webapp:react:views`) {
// exportPath = `${appSrcRoot}/components/views/${refs.id}/versions/${refs.version}.tsx`
tasks.push({
path: `${appSrcRoot}/components/views/${refs.id}.tsx`,
data: `/*
[PLACEHOLDER COMPONENT]
> calls to this component are pre-replaced by @/_cofounder/vite-plugin
> to edit code for this component, you should go to :
@/_cofounder/generated/views/${refs.id}/{version_you_want_to_edit}.tsx
*/`,
});
tasks.push({
path: `${appSrcRoot}/_cofounder/generated/views/${refs.id}/empty.tsx`,
data: `import React from "react";
const {{ID}}: React.FC<any> = (props) => {
return (
<div className="bg-[#eee] text-black text-lg p-4 m-2 rounded">
<strong>{{ID}}</strong> placeholder
<br /><div className="m-2 text-base p-4 bg-[#222] rounded text-white">
To browse other versions<br/>
Use ⌘+K / CMD+K and hover here
</div>
</div>
);
};
export default {{ID}};
`.replaceAll("{{ID}}", refs.id),
});
tasks.push({
path: `${appSrcRoot}/_cofounder/generated/views/${refs.id}/${refs.version}.tsx`,
data: data.content.data.tsx,
});
// write meta.json
let versions = [];
try {
versions = fs
.readdirSync(`${appSrcRoot}/_cofounder/generated/views/${refs.id}/`)
.filter((filename) => filename.endsWith(".tsx"))
.map((filename) => path.basename(filename, ".tsx"));
} catch (e) {
false;
// no dir there yet
}
tasks.push({
path: `${appSrcRoot}/_cofounder/generated/views/${refs.id}/meta.json`,
data: JSON.stringify(
{
versions: [...new Set([...versions, "latest"])],
choice: "latest",
},
null,
"\t",
),
});
/*
<-------- should also merge {dependencies} with current packages.json (either directly in app , or op:state:settings:... preferably latter ; to webapp:react:packages )
*/
}
if (id === `webapp:layout:views`) {
// exportPath = `${appSrcRoot}/components/views/${refs.id}/versions/${refs.version}.tsx`
const exportPath = `${appRoot}/public/_cofounder/generated/layouts/views/${refs.id}.${refs.version}.png`;
const exportData = data.content.data.render.image;
tasks.push({
path: exportPath,
data: exportData,
image: true,
});
}
if (id === `settings:preferences:versions`) {
/*
for now, only handle preference exports for views || sections
*/
const _category = Object.keys(data.content.data)[0];
const _id = Object.keys(data.content.data[_category])[0];
const _version = data.content.data[_category][_id];
if (_category === `views` || _category === `sections`) {
// update meta json on @/_cofounder/generated/{_category}/{id}
let versions = [];
try {
versions = fs
.readdirSync(`${appSrcRoot}/_cofounder/generated/${_category}/${_id}/`)
.filter((filename) => filename.endsWith(".tsx"))
.map((filename) => path.basename(filename, ".tsx"));
} catch (e) {
false;
}
tasks.push({
path: `${appSrcRoot}/_cofounder/generated/${_category}/${_id}/meta.json`,
data: JSON.stringify(
{
versions: [...new Set([...versions, _version])],
choice: _version,
},
null,
"\t",
),
});
}
}
if (id === `settings:config:package`) {
/*
data.content.data : {
[backend || webapp] : {
dependencies? : {}, //<--- this instead of list for merging while saving :)
env?: {},
}
}
load boilerplate package.json,
try load export/.../package.json else {}
merge dependencies of both data.content.data[target].dependencies
if (export/.../) merge with that package
else merge with boilerplate package and export
only save if diff ; else might restart active dev nodemon every single time ...
*/
Object.keys(data.content.data).map((target) => {
// target : "backend" || "webapp"
Object.keys(data.content.data[target]).map((category) => {
// category : "dependencies" || "env"
const boilerplateDir = `../boilerplate/${target === "backend" ? "backend" : target === "webapp" ? "vitereact" : false}-boilerplate`;
const exportDir =
target === "backend" ? backendRoot : target === "webapp" ? appRoot : false;
if (category === "dependencies") {
const newDependencies = Object.keys(
data.content.data[target].dependencies,
);
const boilerplatePackage = JSON.parse(
fs.readFileSync(`${boilerplateDir}/package.json`, "utf8").toString(),
);
let exportedProjectPackage = { dependencies: {}, devDependencies: {} };
try {
exportedProjectPackage = JSON.parse(
fs.readFileSync(`${exportDir}/package.json`, "utf8").toString(),
);
} catch (e) {
console.error(`op:project:_exportOnsave:error : ${e}`);
}
console.dir(
{
"debug:op:project:_exportOnSave : settings:config:package": {
[target]: {
[category]: {
boilerplateDir,
exportDir,
boilerplatePackage,
exportedProjectPackage,
},
},
},
},
{ depth: null },
);
const previousDevDependencies = [
...new Set([
...Object.keys(boilerplatePackage.devDependencies),
...Object.keys(exportedProjectPackage.devDependencies),
]),
];
const previousDependencies = [
...new Set([
...Object.keys(boilerplatePackage.dependencies),
...Object.keys(exportedProjectPackage.dependencies),
...previousDevDependencies,
]),
];
const updateDependencies = newDependencies.some(
(dep) => !previousDependencies.includes(dep),
);
if (updateDependencies) {
const dependenciesToAdd = Object.fromEntries(
[
...new Set(
newDependencies.filter((dep) => !previousDependencies.includes(dep)),
),
].map((dep) => [dep, "*"]),
);
// filter out devDependencies keys so it doesnt move everything to dependencies on export to package.json
const mergedDependencies = Object.fromEntries(
Object.entries(
merge(
merge(
boilerplatePackage.dependencies,
exportedProjectPackage.dependencies,
),
dependenciesToAdd,
),
).filter(([key]) => !previousDevDependencies.includes(key)),
);
let newPackageJson;
if (exportedProjectPackage.dependencies) {
// if exported package.json exists ; merge with rest and export
newPackageJson = JSON.stringify(
merge(exportedProjectPackage, { dependencies: mergedDependencies }),
null,
2,
);
} else {
// else merge with boilerplate package.json and export
newPackageJson = JSON.stringify(
merge(boilerplatePackage, { dependencies: mergedDependencies }),
null,
2,
);
}
console.dir(
{
"debug:op:project:_exportOnSave : settings:config:package": {
[target]: {
[category]: {
mergedDependencies,
newPackageJson,
},
},
},
},
{ depth: null },
);
tasks.push({
path: `${exportDir}/package.json`,
data: newPackageJson,
dependencies: true,
});
}
}
if (category === "env") {
// applies to backend only
const envData = data.content.data[target].env;
if (Object.keys(envData).length) {
const envString = Object.entries(envData)
.map(([key, value]) => `${key}=${value}`)
.join("\n");
console.dir(
{
"debug:op:project:_exportOnSave : settings:config:package": {
[target]: {
[category]: {
env: envData,
envString,
},
},
},
},
{ depth: null },
);
tasks.push({
path: `${exportDir}/.env`,
data: envString,
});
}
}
});
});
const _category = Object.keys(data.content.data)[0];
const _id = Object.keys(data.content.data[_category])[0];
const _version = data.content.data[_category][_id];
if (_category === `views` || _category === `sections`) {
// update meta json on @/_cofounder/generated/{_category}/{id}
let versions = [];
try {
versions = fs
.readdirSync(`${appSrcRoot}/_cofounder/generated/${_category}/${_id}/`)
.filter((filename) => filename.endsWith(".tsx"))
.map((filename) => path.basename(filename, ".tsx"));
} catch (e) {
false;
}
tasks.push({
path: `${appSrcRoot}/_cofounder/generated/${_category}/${_id}/meta.json`,
data: JSON.stringify(
{
versions: [...new Set([...versions, _version])],
choice: _version,
},
null,
"\t",
),
});
}
}
await Promise.all(
tasks.map(async (task) => {
const dir = path.dirname(task.path);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
if (!task.image) {
fs.writeFileSync(task.path, task.data, "utf8");
} else {
// case by case :
// local ? copy paste from local path
// url ? fetch and write
if (task.data?.local?.length) {
const sourcePath = task.data.local;
await fsextra.copyFile(sourcePath, task.path);
} else if (task.data?.url?.length) {
const response = await fetch(task.data.url);
if (!response.ok) {
throw new Error(`Failed to fetch image from ${task.data.url}`);
}
const buffer = await response.buffer();
fs.writeFileSync(task.path, buffer);
}
}
if (
task.dependencies &&
process.env.AUTOINSTALL_ENABLE &&
JSON.parse(process.env.AUTOINSTALL_ENABLE.toLowerCase())
) {
const dependenciesRootPath = task.path.split("/").slice(0, -1).join("/");
console.log(
`\x1b[33m> dependencies updated for : ${dependenciesRootPath}\n> now running 'npm i' inside that folder\x1b[0m`,
);
execSync(`npm i`, {
stdio: "inherit",
cwd: dependenciesRootPath, // folder where package.json is
});
}
}),
);
}
async function opProjectStateUpdate({ context, data }) {
// save, modular
/*
aim for stream structure
*/
/*
context : { project``, }
data: {
local: bool,
cloud: bool,
operation: {
id: "ui:code:lalala",
refs: {
[id] : "id value to replace etc",
[otherId] : "some value etc",
}
},
type: enum start,stream,end
stream: "" || false,
content: {
// should have key here as would be in state :: edge case, how to deal with '.' paths in object ?
key : "" // state key ? ie. pm.prd ; uxsitemap.views.whatever
data : {}
}
}
*/
/*
add :
_created?
_updated
*/
/*
update stream only if cloud
*/
const { project } = context;
const { operation, type, stream, content } = data;
// const [ local , cloud ] = [ process.env.STATE_LOCAL , process.env.STATE_CLOUD];
const { id, refs } = operation;
/*
cases of start/stream/end
*/
const query = {
path: modules[id],
data: {},
};
const ogPath = `${query.path}`;
if (refs) {
Object.keys(refs).map((ref) => {
query.path = query.path.replace(`{${ref}}`, refs[ref]);
});
}
if (type === `start`) {
query.data._created = Date.now();
query.data._processing = true;
}
if (type === `end`) {
query.data._updated = Date.now();
query.data._processing = false;
// query.data = { ...query.data, ...content }
}
if (content) query.data = { ...query.data, ...content };
console.dir({ "debug:op:project:state:update": { query } }, { depth: null });
if (
process.env.STATE_LOCAL &&
JSON.parse(process.env.STATE_LOCAL.toLowerCase())
) {
const localPath = `db/projects/${project}/state/${query.path}.yaml`;
const dir = path.dirname(localPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
if (config.merge.includes(id)) {
try {
const previous = yaml.parse(fs.readFileSync(localPath, "utf8").toString());
query.data = merge(previous, query.data);
} catch (e) {
console.dir({
"op:project:update:error": `no previous state found for ${id}, will write new instead of merge`,
});
}
}
fs.writeFileSync(localPath, yaml.stringify(query.data), "utf8");
}
if (
process.env.STATE_CLOUD &&
JSON.parse(process.env.STATE_CLOUD.toLowerCase())
) {
if (refs) {
// need to write dummy timestamp in docs in case of firestore ; to be able to query subcollections
// query.path find index of "}" and split there+1, replace, log dummy timestamp
let subs = [];
for (let i = 0; i < ogPath.length; i++) {
if (ogPath[i] === "}") {
let sub = ogPath.slice(0, i + 1);
Object.keys(refs).map((ref) => {
sub = sub.replace(`{${ref}}`, refs[ref]);
});
subs.push(sub);
}
}
await Promise.all(
subs.map(async (p) => {
await utils.firebase.doc.update({
path: `/db/userdata/projects/${project}/state/${p}`,
data: { _created: Date.now() },
});
}),
);
}
query.path = `/db/userdata/projects/${project}/state/${query.path}`;
if (config.merge.includes(id)) {
query.merge = true;
}
await utils.firebase.doc.update(query);
}
if (
process.env.AUTOEXPORT_ENABLE &&
JSON.parse(process.env.AUTOEXPORT_ENABLE.toLowerCase()) &&
config.exports.includes(id)
)
await _exportOnSave({ context, data });
}
async function opProjectStateLoad({ context, data }) {
// should have local || cloud strategies
const { project } = context;
// const [local, cloud] = [process.env.STATE_LOCAL, process.env.STATE_CLOUD];
try {
if (
process.env.STATE_LOCAL &&
JSON.parse(process.env.STATE_LOCAL.toLowerCase())
)
return await utils.load.local({ project });
if (
process.env.STATE_CLOUD &&
JSON.parse(process.env.STATE_CLOUD.toLowerCase())
)
return await utils.load.cloud({ project });
} catch (e) {
console.error(`op:project:state:load:error : ${e}`);
}
console.log(`found no previous local / cloud state for project : ${project}`);
return {};
}
async function opProjectStateExport({ context, data }) {
// tons to update , just disregard this for now
return;
// force export full project ; from {data}
}
async function opProjectStateSetup({ context, data }) {
// if local export enabled, duplicate boilerplate
const { project } = context;
const dirs = [
{
source: `../boilerplate/backend-boilerplate`,
target: `${process.env.EXPORT_APPS_ROOT}/${project}/backend`,
},
{
source: `../boilerplate/vitereact-boilerplate`,
target: `${process.env.EXPORT_APPS_ROOT}/${project}/vitereact`,
},
];
for (const { source, target } of dirs) {
// Copy the directory from source to target while respecting .gitignore
await fsextra.copy(source, target, {
filter: (src) => {
// Respect .gitignore by checking if the file is not listed in .gitignore
const ignoreFile = `${source}/.gitignore`;
if (fs.existsSync(ignoreFile)) {
const ignoreList = fs
.readFileSync(ignoreFile, "utf-8")
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
return !ignoreList.some((ignorePattern) => src.includes(ignorePattern));
}
return true; // If no .gitignore, copy everything
},
recursive: true, // Ensure folders are created recursively
});
}
await fsextra.copyFile(
`../boilerplate/package.json`,
`${process.env.EXPORT_APPS_ROOT}/${project}/package.json`,
);
await fsextra.copyFile(
`../boilerplate/README.md`,
`${process.env.EXPORT_APPS_ROOT}/${project}/README.md`,
);
// write meta.json
fs.writeFileSync(
`${process.env.EXPORT_APPS_ROOT}/${project}/vitereact/src/_cofounder/meta.json`,
JSON.stringify({ project }),
);
}
async function opProjectStateSave({ context, data }) {
// save, full current state of project
}
export default {
"op:PROJECT::STATE:UPDATE": opProjectStateUpdate,
"op:PROJECT::STATE:LOAD": opProjectStateLoad,
"op:PROJECT::STATE:SETUP": opProjectStateSetup,
"op:PROJECT::STATE:EXPORT": opProjectStateExport,
// "op:PROJECT::STATE:SAVE": opProjectStateSave,
};

View File

@@ -0,0 +1,18 @@
import utils from "@/utils/index.js";
async function opRenderLayout({ context, data }) {
/* ;; op:RENDER::LAYOUT
render either { view , section , block } using utils.render and svg stuff
in : -> { svg{string``} , mode`view||...` , ...(designSystem,saveFilepath...) }
out : ["svg","image"]
*/
// const { svg , mode } = data // { svg{string``} , mode`view||...` }
return await utils.render.svg({
...data,
// saveFilepath: `./dump/renders/_opRenderLayoutDebug_${data.mode}_${Date.now()}.png`,
});
}
export default {
"op:RENDER::LAYOUT": opRenderLayout,
};

View File

@@ -0,0 +1,345 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function pmBrdAnalysis({ context, data }) {
const { pm, db } = data;
const { details, prd, frd, drd } = pm;
/*
should be 2 (3?) steps :
determine if needs { rest api , realtime socket io api }
make structure
*/
const backendPrompt = [
{
role: "system",
content: `you are an expert product manager and software architect and API designer ;
your role is to determine, based on the provided analysis documents for the app project in development, the specfications of the app backend
your task is very straightforward :
- based strictly on provided docs and outlined features, determine whether, yes or no, for the core features of the app MVP to be implemented, the backend :
> requires a RESTful API ?
> requires realtime (ie. websockets) ?
you will answer exactly in this format, delimited by \`\`\`yaml :
\`\`\`yaml
backend:
requirements:
restApi:
justifyYourAnswer: "write your reasoning for your answer in case it is true"
required: boolean # whether the backend requires or no a REST API
realtimeWebsockets:
justifyYourAnswer: "write your reasoning for your answer in case it is true"
required: boolean # whether the backend requires or no a REST API
\`\`\`
answer in strict parseable Yaml format, exactly in the provided format structure
your answer should start with : \`\`\`yaml
you will be tipped $9999
`,
},
{
role: "user",
content: `\`\`\`app-project:description
${details.text}
\`\`\``,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:features-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `determine the backend specifications in terms of whether the backend needs a REST API , and whether it needs realtime Websockets.
your answer should start with : \`\`\`yaml
you are a genius
`,
},
];
const backendStructureRequirements = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `gpt-4o-mini`, //`gpt-4o`,
messages: backendPrompt,
preparser: `backticks`,
parser: `yaml`,
},
})
).generated;
const messages = [
{
role: "system",
content: `you are an expert product manager and software architect and backend and server and API designer
your job is to consult the provided web app details & analysis documents
in order to create a comprehensive and full Backend Requirements Document (BRD) for it
the emphasis are user-facing features,
based on the expected features and different journeys of different users in the web app
- your role is to conduct the analysis required to design the user-facing server of the provided task
- do a thorough analysis of the provided task
---
- think from all possibles perspectives, put yourself in situation, to make sure your server analysis is fully comprehensive and ready to be developed
- ask yourself:
* what are the features involved in the user-facing server and that is called by the frontend ?
* if a server API is required, what are all the routes required by features expected to be seen by users in the frontend ? what should go in their schemas ? (not technical, rather analytical description from a feature perspective)
* if realtime features are required, what are all the events required by features expected to be seen by users in the frontend ? what should go in their schemas ? (not technical, rather analytical description from a feature perspective)
- your analysis will be used to make a prod-ready backend and will be responsible for an app used by thousands of users, instantly
- your aim is to cover all use cases, as the expert product manager & architect you are
> analyze the task thoroughly, then reply with your analysis in markdown format, in a well-formatted document to give to backend devs
---
> your role here is not the implementation itself, you are the product architect consultant
> your role is to analyze the requirements for all scenarios required by all features
ask yourself :
* am i covering all needed server features?
* am i covering all features that the user expects ?
* if a feature necessitates the use of an external API (ie. checking a stock price , generating an ai image, advanced features that need the use of an external API, etc ...)
important : the backend already has DB and storage capabilities , so DO NOT MENTION DB OR STORAGE AS EXTERNAL APIS ! THOSE ARE ALREADY IMPLEMENTED INTERNALLY IN THE BACKEND !
am i describing the details of what is needed ?
* am i properly aligning my server design details with other design detail aspects of the project such as DB structure ?
in order to ensure your analysis as a product architect consultant has covered every feature requirement
> your job is to make thorough, critical analysis work which will be provided as documentation for devteams to implement
not a technical implementation, rather a thorough analysis, in plain language, of all expected features and their details
> try to outdo yourself by thinking of what might be omitted in advance
- the goal server should be comprehensive will be used as reference to build the app's MVP backend
- cover all cases ; but : data-related tasks only (ie. you are making a mock server with api and/or realtime for user-facing data operations)
---
> very important : for the current purpose of the BRD, the environment will be a mock prototype environment
do not bother with security details etc, have the requirements for the mock prototype
do not hang on very technical details (unless specifically emphasized), as the target is a mock dev prototype env : features functionality is the aim, not advanced technical coverage !
> SHOULD COVER DATA RELATED TASKS ONLY !
> THE MOCK SERVER YOU ARE MAKING IS FOR USER-FACING DATA OPERATIONS, NOT FRONTEND / SERVING STATIC STUFF !
> DATA RELATED TASKS ONLY !
---
your analysis is concerned with these two aspects aspects :
> if the app backend needs a server API , conduct the analysis regarding all the API needs
> if the app backend needs realtime Websockets , conduct the analysis regarding all the realtime events needed
you can only write about these aspects (either one of them or both , depending on whats provided in task documents )
important : DO NOT ANALYZE ANYTHING IN THE BACKEND BESIDES THESE 2 ASPECTS AND THEIR RELATIONS TO USER-FACING FEATURES !!
---
again,
> SHOULD COVER DATA RELATED TASKS ONLY !
> THE MOCK SERVER YOU ARE MAKING IS FOR USER-FACING DATA OPERATIONS, NOT FRONTEND / SERVING STATIC STUFF !
> DATA RELATED TASKS ONLY !
---
important :
use snake_case for any naming you do
---
your reply will be directly transferred as the final BRD document, so do not put anything else in your reply besides the BRD document
no extra comments or surrounding anything, only the markdown-formatted COMPREHENSIVE 100% COVERAGE AMAZING BEAUTIFUL GENIUS SUPER DETAILED 10/10 ARD DOCUMENT
your reply should start with : "\`\`\`markdown" and end with "\`\`\`"
you will be tipped $99999 + major company shares for nailing it perfectly off the bat`,
},
{
role: "user",
content: `\`\`\`app-project:description
${details.text}
\`\`\``,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:features-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`DRD:database-requirements-document
${drd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`DB:specs
${yaml.stringify(db)}
\`\`\``,
},
{
role: "user",
content: `\`\`\`BACKEND:specs-requirements
${yaml.stringify(backendStructureRequirements)}
\`\`\``,
},
{
role: "user",
content: `Conduct a comprehensive analysis for the Backend Requirements Document that considers all personas and features required, in markdown format (justify your reasoning whenever possible)
---
Refer to this general document structure to guide you
\`\`\`BRD:general-structure
I. General, Personas, Features
[...]
II. REST API
II.A. Justification & Reasoning
If app needs REST API, provide your reasoning
II.B. API Endpoints (if applies)
3.B.1. [Endpoint]
Method & Path
Extended Description
Analyze and describe what the function does
Analysis
Interaction with <> DB
Analyze how does function interact with database based on provided DB details and schemas
ask yourself questions such as :
What fields does it need to insert / get / update / delete / ... for each operation ?
Based on provided DB details, does it need to create data on the fly such as ids / dates / ... ?
Does it need to insert data in multiple tables to not make DB conflicts ?
Be very specific & detailed into exactly how the relationships to <> DB tables work in this function
justify any answer by including snippets from the provided DB postgres code and elaborating
remember : the backend is tasked with creating any primitive required by db (ie. ids , ...),
as you can tell from the postgres code
make things 100% perfectly congruent in your analysis
Include any additional important analysis notes
Interaction with <> External APIs
Analyze if function needs to interact with external APIs for needed capabilities, and if so describe
Remember : App already has DB and storage , so external APIs would be external capabilities outside of these 2
Add any important general analysis notes
Data Details
Auth
Does function requires the user to provided an auth token ?
Request
Body content type (json , form , ... ?)
Schema
Response
Content type
Schema
Additionals details / notes (if applies)
[...]
II. Realtime Websockets (if applies)
III.A. Justification & Reasoning
If app needs realtime events, provide your reasoning
III.B. Events (if applies)
3.B.1. [Event]
Event name
Extended Description
Analyze and describe what the function does
Analysis
Interaction with <> DB
Analyze how does function interact with database based on provided DB details and schemas
ask yourself questions such as :
What fields does it need to insert / get / update / delete / ... for each operation ?
Based on provided DB details, does it need to create data on the fly such as ids / dates / ... ?
Does it need to insert data in multiple tables to not make DB conflicts ?
Be very specific & detailed into exactly how the relationships to <> DB tables work in this function
justify any answer by including snippets from the provided DB postgres code and elaborating
remember : the backend is tasked with creating any primitive required by db (ie. ids , ...),
as you can tell from the postgres code
make things 100% perfectly congruent in your analysis
Include any additional important analysis notes
Interaction with <> External APIs
Analyze if function needs to interact with external APIs for needed capabilities, and if so describe
Remember : App already has DB and storage , so external APIs would be external capabilities outside of these 2
Add any important general analysis notes
Data Details
Auth
Does function requires the user to provided an auth token ?
Request payload
Schema
Response payload
Schema
Additional details / notes (if applies)
[...]
IV. Additional Notes
Any additional notes worth mentionning regarding the backend requirements
\`\`\`
---
you're a genius`,
},
];
const brd = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages,
preparser: `backticks`,
parser: false,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "pm:brd",
},
type: `end`,
content: {
key: "pm.brd",
data: brd,
},
},
});
const backendRequirements = backendStructureRequirements.backend.requirements;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "backend:requirements",
},
type: `end`,
content: {
key: "backend.requirements",
data: backendRequirements,
},
},
});
return { pm: { brd }, backend: { requirements: backendRequirements } };
}
export default {
"PM:BRD::ANALYSIS": pmBrdAnalysis,
};

View File

@@ -0,0 +1,139 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function pmDrdAnalysis({ context, data }) {
/* ;; PM:DRD::ANALYSIS
make {userdetails,prd,frd,FJMD} -> DRD analysis
out : ["pm"]
*/
const { pm } = data;
const { details, prd, frd, fjmd } = pm;
// const {text , attachments} = details
const messages = [
{
role: "system",
content: `you are an expert product manager and database designer
your job is to consult the provided web app details, Product Requirements Document, Features Requirements Documents & Features Journeys Map Document
in order to create a comprehensive and full Feature Database Requirements Document (DRD) for it
---
the emphasis are user-facing features,
based on the expected features and different journeys of different users in the web app
- your role is to conduct the analysis part for the provided app in development's DB part
DB schemas analysis should be comprehensive and cover EVERYTHING required by the app MVP, and nothing more - no shiny secondary features, but nothing less than 100% comprehensive for every single expected functionality in production
- your current role is to do a thorough analysis of the provided task and answer with your analysis in markdown format
- think from perspectives of multiple personas, put yourself in situation, to make sure your DB schemas reply is fully comprehensive and ready to be used in production exactly as is
- your answer will be pushed to dev teams directly, and will be responsible for an app used by thousands of users
- your aim is to cover all use cases, as the expert product manager you are
- ask yourself:
* what are the key personas that use the app ?
* what are all the schemas required by features expected to be seen by users ?
* and what are all the schemas required internally to cover all features workflows ?
very important :
- in the schemas parts of your analysis , only make use of basic primitives like numbers, strings, json, etc ... no uuid types or any special types etc
- very important : in the schemas parts of your analysis , only use basic primitives like numbers, strings, json, etc ... no uuid types or any special types etc ! very basic primitives only !
---
> analyze the task thoroughly, then reply with your analysis in markdown format
> try to outdo yourself by thinking of what might be omitted, and reviewing your own work super critically in order to do comprehensive analytical work for this app's MVP
> your job is to make thorough analysis work which will be provided as documentation for devteams to implement
> your job is not the implementation, rather it's looking at the problem from all perspective to make sure a thorough job is done,
and asking yourself, for every scenario, what are all the data entries that would be needed to make this function
---
> note : if auth functionalities are present, use an architecture that will be compatible with a simple jwt auth system, which is very simply user and/or email strings(s) and password hash string !
---
important :
use snake_case for any naming you do
---
> very important : for the current purpose of the DRD, the environment will be a mock prototype environment,
do not bother with security details etc, have the DB requirements for the mock prototype
your reply will be directly transferred as the final DRD document, so do not put anything else in your reply besides the DRD document
no extra comments or surrounding anything, only the markdown-formatted COMPREHENSIVE 100% COVERAGE AMAZING BEAUTIFUL GENIUS SUPER DETAILED 10/10 DRD DOCUMENT
your reply should start with : "\`\`\`markdown" and end with "\`\`\`"
you will be tipped $99999 + major company shares for nailing it perfectly off the bat`,
},
{
role: "user",
content: `\`\`\`app-project:description
${details.text}
\`\`\``,
},
// <------ later on, attachments , pdf/img cases etc map
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:features-requirements-document
${frd}
\`\`\``,
},
/*{
role: "user",
content: `\`\`\`FJMD:features-journeys-map-document
${yaml.stringify(fjmd)}
\`\`\``,
},*/
{
role: "user",
content: `Conduct a comprehensive analysis for the DB Requirements Document that considers all personas and features required, in markdown format (justify your reasoning whenever possible)
you're a genius`,
},
];
const drd = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages,
preparser: `backticks`,
parser: false,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "pm:drd",
},
type: `end`,
content: {
key: "pm.drd",
data: drd,
},
},
});
return { pm: { drd } };
}
export default {
"PM:DRD::ANALYSIS": pmDrdAnalysis,
};

View File

@@ -0,0 +1,149 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function pmFjmdAnalysis({ context, data }) {
/* ;; PM:FJMD::ANALYSIS
make {userdetails,prd,frd} -> FJMD analysis
*/
const { pm } = data;
const { details, prd, frd } = pm;
// const {text , attachments} = details
const messages = [
{
role: "system",
content: `you are an expert product manager and product designer
your job is to consult the provided web app details, analysis, PRD & FRD
in order to create a comprehensive and full Feature Journeys Maps Document (FJMD) for it
the emphasis are user-facing features,
based on the expected features and different journeys of different users in the web app
your generated FJMD is very detailed, comprehensive and covers absolutely 100% of everything required for the web app
you are not limited by provided example journeys
your analysis here should cover ALL journey cases (of the app MVP)
while conducting your FJMD, ask yourself:
- am i covering all 100% the purpose and functions required for the app ?
- am i covering all 100% the expected features from all the users' perspectives? even the small details ?
- am i covering all 100% the user journeys ?
- am i covering all details that other product managers might have omitted from my analysis ?
- am i making sure what i am detailing in my FJMD is absolutely 100% comprehensive and ready to be put into development without any alteration ?
conduct and reply with a generated comprehensive perfect FJMD document, yaml-formatted
the reply format should directly be a list of journeys items in valid yaml format, with this structure :
journeys:
- name : "..."
category : "..."
journeyId: "/*like JOUR-01 format*/"
description: "..."
participants: "..."
preconditions: "describe pre-existing conditions or assumptions..."
postconditions: "describe state expected outcomes after completing the journey"
steps : #list of journey steps, correlated with provided FRD (& PRD)
- intent : "..."
userInteraction : "describe how users will interact with the interface"
featuresIds : ["","",...] # list of featureIds involved in this step (featureIds should be exactly as they are mentionned in the FRD features-requirements-documents as 'featureId' ; important else it would break !)
expectedResponse : "detail the expected response from the app"
- [...]
edgeCases: "describe variations of the journey ; ie. what could go wrong, etc ..."
- [...]
---
your FJMD document will be directly put into development
the emphasis are user-facing features;
functional features +interface features to cover 100% of expected features of the web app, 100% of all possible user journeys
no need to bother with non-user-facing features such as security compliance, nor similar non-user-facing technical details
no need to bother with cases too advanced for the web app MVP features (ie. advanced analytics or multilingual or live support; ... unless specified in provided task ! )
> Stay User-Centric: keep the user's perspective front and center throughout the document
emphasize user-facing features and core app MVP features
you are not limited by provided example journeys in other docs
your analysis here should be comprehensive and cover ALL journey cases
think of many different core journeys from different perspectives in different scenarios
be comprehensive and cover it all
your reply will be directly transferred as the final FJMD document
so make sure the content and YAML formatting are both exquisitely perfect as the genius you are
if an app name is not provided, make a fitting one for your analysis and JMD
emphasize user-facing features and core app MVP features
so do not put anything else in your reply besides the Feature Journeys Maps Document as parseable, valid well-formatted YAML format
no extra comments or surrounding anything, only the YAML-formatted PARSEABLE VALID COMPREHENSIVE 100% COVERAGE AMAZING BEAUTIFUL FEATURES JOURNEY MAPS DOCUMENT
your reply should start with : "\`\`\`yaml" and end with "\`\`\`"
you will be tipped $999 you are a genius`,
},
{
role: "user",
content: `\`\`\`app-project:description
${details.text}
\`\`\``,
},
// <------ later on, attachments , pdf/img cases etc map
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:features-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `implement the Features Journey Maps Documents (FRJD) for all the core journeys for different scenarios
it is expected to be very comprehensive and detailed ; in a VALID PARSEABLE YAML format
you're a genius`,
},
];
/*
const fjmd = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages,
preparser: `backticks`,
parser: `yaml`,
},
})
).generated;
*/
console.error(`skipping features journey map doc`);
const fjmd = ``;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "pm:fjmd",
},
type: `end`,
content: {
key: "pm.fjmd",
data: fjmd,
},
},
});
return { pm: { fjmd } };
}
export default {
"PM:FJMD::ANALYSIS": pmFjmdAnalysis,
};

View File

@@ -0,0 +1,117 @@
import utils from "@/utils/index.js";
async function pmFrdAnalysis({ context, data }) {
/* ;; PM:FRD::ANALYSIS
make {userdetails,prd} -> FRD analysis
*/
const { pm } = data;
const { details, prd } = pm;
// const {text , attachments} = details
const messages = [
{
role: "system",
content: `you are an expert product manager and product designer
your job is to consult the provided web app details & analysis PRD,
and create a full Features Requirements Document (FRD) for it
the emphasis are user-facing features,
based on the expected features and different journeys of different users in the web app
your generated FRD is very detailed, comprehensive and covers absolutely 100% of everything required for the web app
while conducting your FRD, ask yourself:
- am i covering all 100% the purpose and functions required for the app ?
- am i covering all 100% the expected features from all the users' perspectives? even the small details ?
- am i covering all 100% the user journeys ?
- am i covering all details that other product managers might have omitted from my analysis ?
- am i making sure what i am detailing in my FRDis absolutely 100% comprehensive and ready to be put into development without any alteration ?
conduct and reply with a generated comprehensive perfect FRD document, markdown-formatted
the reply format should directly be a bulletpoints list of features items, each has 6 keys :
features:
name , category , featureId (/*like 'XXXX-01' format*/) , description , detailedDiscussion , extensiveDetailedBulletpoints
---
your FRD document will be directly put into development
the emphasis are user-facing features;
functional features + interface features to cover 100% of expected features of the web app, 100% of all possible user journeys
no need to bother with non-user-facing features such as security compliance, nor similar non-user-facing technical details
no need to bother with cases too advanced for the web app MVP features (ie. advanced analytics or multilingual or live support; ... unless specified in provided task ! )
emphasize user-facing features and core app MVP features
your reply will be directly transferred as the final FRD document
so make sure the content is comprehensive and ensuing app UX is perfect as the genius you are
if an app name is not provided, make a fitting one for your analysis and FRD
emphasize user-facing features and core app MVP features
so do not put anything else in your reply besides the FRD DOC as parseable, valid well-formatted dpc
no extra comments or surrounding anything, only the VALID COMPREHENSIVE 100% COVERAGE AMAZING BEAUTIFUL FRD DOCUMENT
your reply should start with : "\`\`\`markdown" and end with "\`\`\`"
you will be tipped $999 you are a genius`,
},
{
role: "user",
content: `\`\`\`app-project:description
${details.text}
\`\`\``,
},
// <------ later on, attachments , pdf/img cases etc map
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `implement the Features Requirements Document (FRD)
it should span and cover all 100% of user-facing features and for all 100% of journeys required and will be directly pushed to development
absolutely no feature would be missing ; every detail and description for 100% of every feature required
it is expected to be 100% comprehensive and super detailed
you're a genius`,
},
];
const frd = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages,
preparser: `backticks`,
parser: false,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "pm:frd",
},
type: `end`,
content: {
key: "pm.frd",
data: frd,
},
},
});
return { pm: { frd } };
}
export default {
"PM:FRD::ANALYSIS": pmFrdAnalysis,
};

View File

@@ -0,0 +1,127 @@
import utils from "@/utils/index.js";
async function pmPrdAnalysis({ context, data }) {
/* ;; PM:PRD::ANALYSIS
make userprovided details -> PRD analysis ; user can have text + {pdf , images} (now just text), later extend
*/
const { pm } = data;
const { details } = pm;
const { text, attachments } = details;
// const {text , attachments} = details
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "pm:details",
},
type: `end`,
content: {
key: "pm.details",
data: details,
},
},
});
const messages = [
{
role: "system",
content: `you are an expert product manager and product designer
your job is conduct the analysis for the provided web app project task and create a full PRD document for it
your analysis is very detailed, comprehensive and covers absolutely 100% of everything required for the web app
while conducting your PRD, ask yourself:
- what is a detailed description of the app, and all it's expected features ?
- what are all the purpose and functions required for the app ?
- am i covering all the expected features from the users' perspectives? even the small details ?
am i sure i am not missing anything important ?
- what are the personas ? what are their user stories ? what are all the expected features ?
- what are all the features ?
- am i covering all the expected features from the users' perspectives? even the small details ?
am i sure i am not missing anything important ?
- what about the user journeys ? am i covering all possible journeys for all users ?
- what could i or other product managers be potentially omitting and that shouldn't be the case ?
- am i making sure what i am detailing in my PRD is absolutely 100% comprehensive and ready to be put into development without any alteration nor pre-assumption that might lead to important omissions ? am i detailing all that is needed ?
after you finalize your PRD,
add an extra part, called "Additional Analysis", where you criticize (very critically) the work you just did;
ask yourself :
- what might have been omitted from my analysis that should have gone into the web app MVP requirements ?
- do not bother with secondary or tertiary things (ie. accessibility or similar advanced non-MVP stuff), ask yourself instead, critically : what core web app MVP features or journeys did i not previously mention ? what are their details ?
conduct and reply with a generated comprehensive perfect PRD document, markdown-formatted
your PRD document will be directly put into development,
so make sure the content and MD formatting are both exquisitely perfect as the genius you are
if an app name is not provided, make a fitting one for your analysis and PRD
the aim of the PRD are web app facing requirements
no need to bother with non-web-app features such as security compliance or similar non-web-app-facing technical details
no need to bother with non-MVP features (ie. advanced cases such as analytics or support or i18n etc ... focus on the MVP to cover 100% of expected features ) - unless explicitly specified in the task descriptions ofc
focus on what's important and detail it to the maximum, leave nothing !
your reply will be directly transferred as the final PRD document, so do not put anything else in your reply besides the PRD document
no extra comments or surrounding anything, only the markdown-formatted COMPREHENSIVE 100% COVERAGE AMAZING BEAUTIFUL GENIUS SUPER DETAILED 10/10 PRD DOCUMENT
your reply should start with : "\`\`\`markdown" and end with "\`\`\`"
you will be tipped $999
you're a genius
`,
},
{
role: "user",
content: `\`\`\`app-project:description
${text}
\`\`\``,
},
// <------ later on, attachments , pdf/img cases etc map
{
role: "user",
content: `Conduct your analysis and make sure you do not miss any feature or detail !
you are a genius`,
},
];
console.dir({ __debug_pmPrdAnalysis: { messages } });
const prd = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages,
preparser: `backticks`,
parser: false,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "pm:prd",
},
type: `end`,
content: {
key: "pm.prd",
data: prd,
},
},
});
return { pm: { prd } };
}
export default {
"PM:PRD::ANALYSIS": pmPrdAnalysis,
};

View File

@@ -0,0 +1,221 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function pmUxdmdAnalysis({ context, data }) {
/* ;; PM:UXDMD::ANALYSIS
{pm docs , db , openapi? , uxsitemap {analysis,struct,...}?} -> (<> crossanalysis) to make UX Datamap Doc
*/
const { pm, db, backend } = data;
const { details, prd, frd, drd, uxsmd, brd } = pm;
const messages = [
{
role: "system",
content: `- you are a genius Product Manager & Software Archtect
- your role is to conduct the analysis required to design the frontend app architecture for the provided project in its details
- think from perspectives of multiple personas, put yourself in situation, to make sure your app architecture analysis is fully comprehensive and ready to be developed
- ask yourself:
* what are the journeys involved in the app frontend ?
* what are all the routes , views , slugs , props , URL parameters , auth restrictions, required by features expected to be seen by users in the frontend ?
* what should go in their schemas ? (not technical, rather analytical description from a feature perspective)
- your analysis will be used to make a prod-ready app and will be responsible for an app used by thousands of users
- your aim is to cover all use cases, as the expert product manager & architect you are
> analyze the task thoroughly, then reply with your analysis in markdown format, in a well-formatted document to give to app designers & devs
> your role here is not the implementation itself, you are the product architect consultant
> your role is to analyze the requirements for all scenarios required by all features
ask yourself :
* am i covering all needed app features?
* am i covering all features that the user expects ?
in order to ensure your analysis as a product architect consultant has covered every feature requirement
> your job is to make thorough, critical analysis work which will be provided as documentation for designers & devteams to implement
not a technical implementation, rather a thorough analysis, of all expected architecture features and their details
---
your aim is to determine, in extreme detail:
I. the structure of the app:
* routes
* what views they link to
* slugs (ie. path /something/:example) if applies
* if route is restricted or not
* URL params (ie. /somepath?param_a=example&param_b=example ) if applies
> important : only refer to views ids specified in provided ux sitemap ! (UV_* and GV_* views)
II. the relationships between views of the app (based on the provided UX sitemap ; (unique views UV_* and shared ui views GV_*) ) & app data (based on provided DB & backend docs & schemas ):
conduct a cross analysis between UX sitemap views <> app data states in order to :
1. determine stateful variables , actions/dynamic functions , params :
1A. if the view has state for dynamic data, describe
1B. if the view should access slug passed into url (ie. /something/:example ), describe
1C. if the view should access URL params and use them for a feature (ie. /somepath?param_a=X&param_b=Y), describe
1D. if the view has actions/dynamic functions like API calls or realtime events, describe in detail
1E. revise and provide your reasoning to make sure you covered all the state/data details required to make all required features work properly
> important : only refer to view ids specified in provided ux sitemap ! (UV_* and GV_* views) , dont hallucinate UI views/components !
2. global app state structure, that is accessed by all views :
* how the app state should be structured to cover the app features, in terms of :
variables & schemas
actions
make sure you only analyze the global app state (which ie. typically holds stuff like auth / notifications / ... )
and not view-specific props and state (as the latter were already detailed in the previous section and should not be mentionned here)
make sure you determine the schemas for the global app state variables
provide examples values for them (based on provided app schemas & DB seed examples), in each case
---
> try to outdo yourself by thinking of what might be omitted, and reviewing your own work super critically in order to do comprehensive analytical work for this app's MVP
- the goal app should be comprehensive, will be used as the reference to build the app
- cover all cases in terms of app architecture ; with high emphasis on details regarding data and states
---
important :
> use snake_case for any naming you do
extremely important :
> ensure full perfect coherence with DB fields names and provided specs names ;
---
your reply will be directly transferred as the final analysis, so do not put anything else in your reply besides the analysis document
no extra comments or surrounding anything, only the markdown-formatted COMPREHENSIVE 100% COVERAGE AMAZING BEAUTIFUL GENIUS SUPER DETAILED 10/10 ANALYSIS DOCUMENT
your reply should start with : "\`\`\`markdown" and end with "\`\`\`"
you will be tipped $99999 + major company shares for nailing it perfectly off the bat`,
},
{
role: "user",
content: `\`\`\`app-project:description
${details.text}
\`\`\``,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:features-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`DRD:database-requirements-document
${drd}
\`\`\`
---
\`\`\`DB:schemas
${yaml.stringify(db)}
\`\`\``,
},
{
role: "user",
content:
`\`\`\`BRD:backend-requirements-document
${brd}
\`\`\`
` +
(!backend?.requirements?.restApi?.required
? ""
: `---
\`\`\`BACKEND:specifications:openAPI
${yaml.stringify(backend.specifications.openapi)}
\`\`\`
`) +
(!backend?.requirements?.realtimeWebsockets?.required
? ""
: `---
\`\`\`BACKEND:specifications:asyncAPI
${yaml.stringify(backend.specifications.asyncapi)}
\`\`\`
` +
`
---
\`\`\`BRD:server:main
${yaml.stringify(backend.server.main)}
\`\`\`
---
note :
> any reference to the backend server should be the local dev URL referred to in docs ; typically : \`http://localhost:1337\`
> if case app needs a global state, global app state should be in the context of one single app redux store \`store.tsx\` that wraps the entire app and includes all that is needed for all global state stuff:
ie. auth for api and/or auth for websockets
ie. if backend has realtime events, realtime events subscriptions
etc ... in one single global state store
`),
},
{
role: "user",
content: `\`\`\`UXSMD:ux-sitemap-document
${uxsmd}
\`\`\``,
},
{
role: "user",
content: `Conduct the analysis for the frontend app architecture and its details in a frotnend app architecture analysis document style - starting with a table of contents, elaborating on everything the task specifies, in extreme detail specifying all that needs specification
extremely important :
> you are absolutely forbidden from instructing in the document about having to create new components or how to structure the project
> you should 100% stick strictly to the provided task !
you're a genius`,
},
];
const uxdmd = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, // `chatgpt-4o-latest`,//`gpt-4o`,
messages,
preparser: `backticks`,
parser: false,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "pm:uxdmd",
},
type: `end`,
content: {
key: "pm.uxdmd",
data: uxdmd,
},
},
});
return {
pm: { uxdmd },
};
}
export default {
"PM:UXDMD::ANALYSIS": pmUxdmdAnalysis,
};

View File

@@ -0,0 +1,159 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function pmUxsmdAnalysis({ context, data }) {
/* ;; PM:UXSMD::ANALYSIS
{pm docs , db , openapi?} -> (<> crossanalysis) to make UX Sitemap doc
*/
const { pm } = data;
const { details, prd, frd } = pm;
const { text, attachments } = details;
const messages = [
{
role: "system",
content: `you are an expert product manager and app designer
your job is to consult the provided web app details and additional documents
in order to create a comprehensive and full UX Sitemap Document (UXSMD) for it
- your current role is to do a thorough analysis of the provided web app requirements and answer with your analysis in markdown format
- make sure your UX Sitemap Document is fully comprehensive and ready to be put in development exactly as is
your answer will be pushed to dev teams directly, and will be responsible for an app used by thousands of users
your aim is to cover all use cases, as the expert app designer you are
---
ask yourself:
I.
* am i covering shared global UI views in my analysis (ie. top navigation, footers, ...) in a separate section,
which also details the components that share them ?
am i assigning unique and expressive title-cased ids to them (in format "GV_{...}" ie. "GV_TopNav" ) ?
am i careful to consider cases of authenticated/unauthenticated
(whether conditionals regarding accessing the view itself or conditionals on its contained elements) to make sure my coverage is not missing things ?
* am i covering all the needed unique UI views ; for all the required features ?
am i assigning unique and expressive title-cased ids to them (in format "UV_{...}" ie. "UV_Landing" ) ?
am i making sure unique views do not include duplicate shared global UI views which were already previously covered ?
am i careful to consider cases of authenticated/unauthenticated (whether conditionals regarding accessing the view itself or conditionals on its contained elements) to make sure my coverage is not missing things ?
* am i extensively describing everything in details for the dev team to have 100% coverage of everything needed through my UX Sitemap Document analysis ?
* am i covering EVERYTHING expected to be present in this web app:
every view (every unique view and every shared global view) expected to be in the app ?
every view's components expected to be in the app to cover all 100% of features and all their details ?
am i covering the views for all workflows, end to end ?
* am i making sure i am covering the core and essential features / views , and not some optional secondary/tertiary not really required stuff ?
II.
* am i describing the functional and features analysis of each view before further detailing it in order to have a cohesive and comprehensive analysis and not omit any details ?
* what are all the requirements needed by features expected to be seen by users in terms of UI views ( unique views and shared global views ) and contained views' components ?
* cross analysis between feature <> ui views required to create in ux sitemap ?
* what are ALL THE VIEWS required by ALL THE REQUIREMENTS required by the user ?
* am i covering all views (unique views and shared global views) ?
with all extensive details and descriptions ?
* am i making sure i am covering the core and essential features / views , and not some optional secondary/tertiary not really required stuff ?
III.
can i make a table for all the cross links analysis between different views in order to establish inter-app navigation relationships ?
can i describe their intent in each case ?
can i also describe how the linking works (in terms of ui elements / user interaction / action taken to trigger the link and where in the view ) ?
Source view | Target View | Intent | Action Description
* am i covering 100% of relations links of whats needed for all in-app navigation, both static and dynamic ?
* am i truly covering all inter-app cross links relations and not missing anything ?
---
> analyze the task thoroughly, then reply with your analysis in markdown format
> try to outdo yourself by thinking of what might be omitted, and reviewing your own work super critically in order to do comprehensive analytical work for this app's MVP
> your job is to make thorough analysis work which will be provided as documentation for devteams to implement
---
> stick to the provided formats and specifications:
UI unique views with ids UV_*
UI global shared views with ids GV_*
do not make up new denominations or types, stick to the task exactly as specified !
---
important :
> do not many any "Container" views (like some GV_GlobalContainer or something) ; DO NOT make any container views to contain other views inside of them !
only make unique UV_* or GV_* shared views : views that serve a functional purpose ; not container views !
---
your reply will be directly transferred as the final UX Sitemap Analysis Document, so do not put anything else in your reply besides the UX Sitemap analysis document
no extra comments or surrounding anything, only the markdown-formatted COMPREHENSIVE 100% COVERAGE AMAZING BEAUTIFUL GENIUS SUPER DETAILED 10/10 UX SITEMAP ANALYSIS DOCUMENT
your reply should start with : "\`\`\`markdown" and end with "\`\`\`"
you will be tipped $9999`,
},
{
role: "user",
content: `\`\`\`app-project:description
${details.text}
\`\`\``,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:features-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `Conduct a comprehensive and detailed analysis for the UX Sitemap Document for the app, in markdown format. elaborate and justify and detail to the greatest extent. make extensive descriptions.
you're a genius`,
},
];
const uxsmd = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages,
preparser: `backticks`,
parser: false,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "pm:uxsmd",
},
type: `end`,
content: {
key: "pm.uxsmd",
data: uxsmd,
},
},
});
return {
pm: { uxsmd },
};
}
export default {
"PM:UXSMD::ANALYSIS": pmUxsmdAnalysis,
};

View File

@@ -0,0 +1,365 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function promptAnalysis({ context, data }) {
const { task } = data;
const { code, decorators, apis } = task;
return [
{
role: "system",
content: `you are an expert backend and node js dev
- your role is to generate an analysis for for functions to implement that may require the use of external APIs , either through API calls or npm sdks
- you are provided with descriptions and contextual code snippets of desired functions, from a node server module
these function are tagged as needing the implementation of external APIs/SDKs for the tasks they are meant to accomplish
- you are also provided with some search results for external APIs for each function from some external APIs that were indexed
> you are to determine whether external API search result(s) are relevant or no for the desired use cases descriptions
> if so , which ones to use and how ? what do they need to run ? how to use them ? how to format their expected response ?
> if no search result is relevant, do you know, about fitting nodejs/npm SDKs/packages or other APIs you are familiar with that are fit for the task ?
and if so, how to use them ?
> note : if a fitting external API is identified and also has SDKs you know about
its prefereable to call the API using the provided openapi / docs instead of the SDK you already know about
( because SDKs might have been updated since your last knowledge base ) ;
use SDKs for when no APIs search results make sense for the analyzed implementation case
> note : if you are using references from provided docs, extracts and include snippets from them inside your analysis to further document your analysis properly
conduct a detailed analysis for each of the ${apis.length} provided functions to implement
your reply should start with : "\`\`\`markdown" and end with "\`\`\`"
you will be tipped $999
you're a genius
`,
},
// each api entry in its own message
...apis.map(({ id, description, snippet, rag }) => {
return {
role: "user",
content: `\`\`\`task:${id}
${yaml.stringify({
functionDescription: description,
contextCodeSnippet: snippet,
})}
\`\`\`
\`\`\`apis-search-results:${id}
${rag.length ? yaml.stringify(rag) : ""}
\`\`\`
`,
};
}),
{
role: "user",
content: `Conduct your analysis each of the ${apis.length} provided functions to implement, with each function in its separate and very detailed section, and make sure you do not miss any useful detail !
be extremely detailed and include every single used reference and detail in your analysis for it to be fully comprehensive and complete
you are a genius`,
},
];
}
async function promptImplementMerge({ context, data }) {
const { pm, db, backend, task } = data;
const { prd, frd, drd, brd } = pm;
const { code, apis, analysis } = task;
const { openapi, asyncapi } = backend.specifications;
/*
should also get BRD here ! important ! ie. so it doesnt do stupid placeholders ?
should provide full code too ? maybe 2 pass implement directly ; implement and revise ?
no need for rag here
*/
return [
{
role: "system",
content: `Your task, as the genius backend dev expert you are, is to generate the full nodejs script for a module, based on the provided specifications and details of the backend in development
- the current code of the server script is provided
the desired updates are provided
> your main task is to add the provided functions , and return a fully functional script that has both the original features and the newly added updates, with everything working perfectly and as expected
---
your role is to implement the full express server for the provided task for the \`server.mjs\` (type: module script)
you will answer in 3 parts :
- analysis , in between \`\`\`markdown\`\`\`\` section
- code , in between \`\`\`mjs\`\`\`\` section
- dependencies and env variables , in between \`\`\`yaml\`\`\`\` section ; where any needed packages to install and needed env variables to setup will be mentionned ; the yaml should have objects : { dependencies : {"package":"version"} , env : {"key" , "temp_value"} } ("dependencies" (for packages) and "env" for env variables (and their temporary values) )
use doublequotes for every string inside the yaml to make sure formatting is good
---
in your analysis, ask yourself :
> what are the added functions ?
> how do i merge all updates perfectly with the working code ?
> is the full flow covered ?
> are all the expected functions fullfilled ?
> am i covering all the parts for all the required updates ?
including imports, functions, db operations, ... ?
are all the new updates congruent with the original code structure, flow, db operations and all that is expected ?
---
for any db requirements, use postgres from \`@electric-sql/pglite\`
- to use postgres, include this snippet in your script :
\`\`\`
import { PGlite } from "@electric-sql/pglite";
const postgres = new PGlite("./db");
/* then, can be used like this :
await postgres.query("SELECT * FROM exampletable;")
*/
// note : the postgres tables + seed were already created before , you can use the postgres directly without configuring it
\`\`\`
postgres is use exactly how is provided in the snippet, do not change anything about loading it / configuring it, else it breaks ;
postgres is imported, initialized and queries EXACTLY AS SHOWN IN THE SNIPPET ! NO OTHER WAY !
---
note : the postgres tables + seed were already created before , you can use the postgres directly without configuring it ; do not create tables in script !
extremely important :
- the DB R/W need to be 100% compatible with the tables and schemas of the provided DB specifications !!
- if it makes use of .env , make your you import \`dotenv\` and \`dotenv.config()\` to read .env before !
---
extremely important :
- you are to implement the entire server as specified in the provided docs , with a focus on DB R/W operations
- you are to implement every single thing needed by the backend server and output one single big working perfect \`server.mjs\` script
- do not assume anything is implemented yet ! you will do 100% of everything needed and output one single big working perfect \`server.mjs\` script
- no placeholders, no hallucinated imports
- again, do not assume anything is implemented yet ! you will do 100% of everything needed and output one single big working perfect \`server.mjs\` script
---
note:
> if ie. some mock data is meant to to store an image url, use a https://picsum.photos/ url with a random seed
super important :
> use snake_case for any new naming you do
> ensure full perfect coherence with DB fields names and all provided specs names
---
extremely important :
- the DB R/W need to be 100% compatible with the tables and schemas of the provided DB specifications !!
- the app flow must be 100% working perfect everywhere
you are a genius + you get tipped $9999999
`,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\`
\`\`\`FRD:features-requirements-document
${frd}
\`\`\`
`,
},
{
role: "user",
content: `
\`\`\`DB:postgres:sql
${db.postgres}
\`\`\`
---
extremely turbo important :
> pay extreme attention to DB details :
> the things that you are expected to provide with inserts :
> should you make a uuid before inserting with postgres query ?
> are there key constraints ?
> is the db querying code using the exact names as in db fields ?
> are you providing everything needed to db every single time ?
`,
},
{
role: "user",
content: `\`\`\`BRD:backend-requirements-document
${brd}
\`\`\``,
},
data.backend?.requirements?.restApi?.required && {
role: "user",
content: `\`\`\`BACKEND:specifications:openAPI
${yaml.stringify(openapi)}
\`\`\``,
},
data.backend?.requirements?.realtimeWebsockets?.required && {
role: "user",
content: `\`\`\`BACKEND:specifications:asyncAPI
${yaml.stringify(asyncapi)}
\`\`\``,
},
{
role: "user",
content: `The functions updates of the original code are the following :
\`\`\`functions:update:tasks
${yaml.stringify({
toUpdate: apis.map(({ description, snippet }) => {
return {
functionDescription: description,
contextCodeSnippet: snippet,
};
}),
})}
\`\`\``,
},
{
role: "user",
content: `The original full script code to update is :
\`\`\`mjs
${code}
\`\`\`
`,
},
{
role: "user",
content: `The analysis of the new updates to make to the server code is in the following :
\`\`\`functions:update:analysis
${analysis}
\`\`\``,
},
{
role: "user",
content: `extremely important :
- you are to implement the entire \`server.mjs\` as specified in the backend specifications , with a focus on DB R/W operations
- you are to implement every single thing needed by the server and output one single big working perfect \`server.mjs\` script
- do not assume anything is implemented yet ! you will do 100% of everything needed and output one single big working perfect \`server.mjs\` script
- no placeholders, no hallucinated imports
---
extremely turbo important :
> pay extreme attention to DB details :
> the things that you are expected to provide with inserts :
> should you make a uuid before inserting with a postgres query ?
> are there key constraints ? should you create something before inserting something else because of contraints ?
> is the db querying code using the exact names as in db fields ?
> are you providing everything needed to db every single time ?
---
- again, do not assume anything is implemented yet ! you will do 100% of everything needed and output one single big working perfect \`server.mjs\` script
- again , you are to implement every single thing needed by the server and output one single big working perfect \`server.mjs\` script
- no placeholders, no hallucinated imports ; one 100% perfect complete working server script
extremely important :
- the DB R/W need to be 100% compatible with the tables and schemas of the provided DB specifications !!
now do the analysis , write the full working script and specify the dependencies+env`,
},
].filter((e) => e);
}
async function promptImplementReview({ context, data }) {
const { task } = data;
const { brd } = pm;
const { code, decorators, apis, analysis, implementations } = task;
/*
maybe double check verify instead ?
*/
return [];
}
async function swarmAugmentBackendExternalapis({ context, data }) {
/*
*/
const { task } = data;
const { code } = task;
const decorators = (await utils.parsers.extract.decorators({ code })).filter(
(item) => item.type === "external-api" || item.type === "external-apis",
);
if (!decorators.length) return {};
// apis RAG
const apis = await Promise.all(
decorators.map(async (item, idx) => {
const { description, snippet } = item;
const ragText = `Description : ${description}\n\nCode Snippet :\n\`\`\`\n${snippet}\n\`\`\``;
return {
id: `fn:${idx + 1}/${decorators.length}`,
description,
snippet,
rag: (
await context.run({
id: `op:INDEXDB::QUERY`,
context,
data: {
index: "apis",
text: ragText,
amount: 5,
},
})
).results,
};
}),
);
data.task.decorators = decorators;
data.task.apis = apis;
const messagesAnalysis = await promptAnalysis({ context, data });
const analysisPass = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages: messagesAnalysis,
preparser: `backticks`,
parser: false,
},
})
).generated;
data.task.analysis = analysisPass;
const messagesImplementMerge = await promptImplementMerge({ context, data });
const { generated } = await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages: messagesImplementMerge,
preparser: false,
parser: false,
},
});
const extraction = await utils.parsers.extract.backticksMultiple({
text: generated,
delimiters: [`markdown`, `mjs`, `yaml`],
});
const { mjs } = extraction;
if (!mjs.length || !extraction.yaml) {
throw new Error(
"swarm:augment:backend:externalApis:generate error - generated code is empty",
);
}
const parsedYaml = extraction.yaml ? yaml.parse(extraction.yaml) : {};
const generatedServer = {
mjs,
dependencies: parsedYaml.dependencies
? Object.fromEntries(
Object.keys(parsedYaml.dependencies).map((key) => [key, "*"]),
)
: [],
env: parsedYaml.env ? parsedYaml.env : {},
timestamp: Date.now(),
};
return generatedServer;
}
export default {
"SWARM:AUGMENT::BACKEND:EXTERNALAPIS": swarmAugmentBackendExternalapis,
};

View File

@@ -0,0 +1,10 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function swarmFixBackend({ context, data }) {}
async function swarmFixWebapp({ context, data }) {}
export default {
"SWARM:FIX::BACKEND": swarmFixBackend,
"SWARM:FIX::WEBAPP": swarmFixWebapp,
};

View File

@@ -0,0 +1,20 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
import dotenv from "dotenv";
dotenv.config();
/*
should check process.env.SWARM_ENABLE
*/
async function swarmReviewServerMain({ context, data }) {}
async function swarmReviewWebappStore({ context, data }) {}
async function swarmReviewWebappRoot({ context, data }) {}
async function swarmReviewWebappView({ context, data }) {}
export default {
"SWARM:REVIEW::SERVER:MAIN": swarmReviewServerMain,
"SWARM:REVIEW::WEBAPP:STORE": swarmReviewWebappStore,
"SWARM:REVIEW::WEBAPP:ROOT": swarmReviewWebappRoot,
"SWARM:REVIEW::WEBAPP:VIEW": swarmReviewWebappView,
};

View File

@@ -0,0 +1,493 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
import { merge, fromPairs } from "lodash-es";
function _chunkify(input_list, chunk_size) {
const chunks = [];
for (let i = 0; i < input_list.length; i += chunk_size) {
chunks.push(input_list.slice(i, i + chunk_size));
}
return chunks;
}
async function uxDatamapStructure({ context, data }) {
/* ;; UX:DATAMAP::ROOT:VIEWS
{...} -> app {routes, slugs, params , views } ; yaml
;; preconsider layout stuff too, either here or in sitemap
out : ["uxdatamap"]
*/
const { pm, backend } = data;
const { prd, frd, brd, uxsmd, uxdmd } = pm;
const messages = [
{
role: "system",
content: `- you are a genius Product Manager & Software Archtect
- your role is to make the frontend app architecture for the provided project , based on the provided task and analysis documents
- your answer should be in the strict provided format that will be defined further
your aim is to determine the:
* the structure of the app:
* global app state structure that is accessed by all views : how the app state should be structured to cover the app features
* routes, what views they link to
* route restrictions
* slugs if applies (ie. path /something/:example), describe
* URL params if applies (ie. /somepath?param_a=example&param_b=example ), describe
- think from perspectives of multiple personas, put yourself in situation, to make sure your app architecture is fully comprehensive and ready to be developed
- ask yourself:
* what are the journeys involved in the app frontend ?
* what are all the routes , views , slugs , props , URL parameters , required by features expected to be seen by users in the frontend ?
* what should go in schemas ?
* am i covering all needed slugs ?
am i covering all URL parameters ?
- your structure will be used to make a prod-ready app architecture and will be responsible for an app used by thousands of users
- your aim is to cover all use cases, as the expert product manager & architect you are
> your answer should strictly be in this format :
\`\`\`yaml
app:
root:
globalState: # global app state variables if applies ; name conventions should try match with dbschemas/openapi schemas for coherence
[name]: # global app state variable name
schema: # variable schema in JS-parseable interace format ; schema should be fully defined including nested fields (you are provided with all the documents and db schemas and openapi etc ... that you need to determine this)
default: # default value to assign to the variable ; should obviously be aligned with the defined schema
example: # example value to assign
...
routes: # list of app routes to cover all features and cases
- description: "..." # concise one sentence description of the route's role
path: "..." # path, including if any slugs (using the /:slug format )
view: "" # view id to render on this route ; should match a provided id for a unique view from the ux sitemap (UV_*), based on the provided analysis
# specify slugs / URL params if applies here
# note : remember there is a strong difference - slugs are (/examplepath/:slug_id) and urlParams are (/somepath?q=example&someparam=somevalue) do not confuse them !
slugs?: # if slugs in path, describe
- name: "..." # slug id as specified in path
intent: "..." # consise one sentence description of its role
...
urlParams?: # does the view expect url params, if so describe each single URLparam individually in detail
- name: "..." # if the view will expect URL params, specify the URL param name
intent: "..." # consise description
example: "exampleValue" # an example of a value it would take - you are required to provide an example here
required?: boolean # if specifying the urlParam is required or optional for the view to function properly
...
\`\`\`
---
it should be comprehensive for the needs required by all the views
> important : if some home or landing view, path should obviously be "/" !
your reply will be directly transferred as the final structure, so do not put anything else in your reply besides the final structure
your reply should start with : "\`\`\`yaml" and end with "\`\`\`"
you will be tipped $99999 + major company shares for nailing it perfectly off the bat`,
},
{
role: "user",
content: `\`\`\`PRD:app-product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:app-features-requirements-document
${yaml.stringify(frd)}
\`\`\``,
},
{
role: "user",
content:
`\`\`\`BRD:backend-requirements-document
${brd}
\`\`\`
` +
(!backend?.requirements?.restApi?.required
? ""
: `---
\`\`\`BACKEND:specifications:openAPI
${yaml.stringify(backend.specifications.openapi)}
\`\`\`
`) +
(!backend?.requirements?.realtimeWebsockets?.required
? ""
: `---
\`\`\`BACKEND:specifications:asyncAPI
${yaml.stringify(backend.specifications.asyncapi)}
\`\`\`
` +
`
---
\`\`\`BRD:server:main
${yaml.stringify(backend.server.main)}
\`\`\`
`),
},
{
role: "user",
content: `\`\`\`UXSMD:ux-sitemap-document
${uxsmd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`UXDMD:ux-sitemap-data-states-crossanalysis-document
${uxdmd}
\`\`\``,
},
];
const uxdatamapStructure = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`chatgpt-4o-latest`, // `chatgpt-4o-latest`,//`gpt-4o`,
messages,
preparser: `backticks`,
parser: `yaml`,
},
})
).generated;
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "architecture:uxdatamap:structure",
},
type: `end`,
content: {
key: `uxdatamap.structure`,
data: uxdatamapStructure.app,
},
},
});
return {
uxdatamap: {
structure: uxdatamapStructure.app, // -> {root{},routes{}}
},
};
}
async function uxDatamapViews({ context, data }) {
/* ;; UX:DATAMAP::VIEWS:SECTIONS
{ ... } -> sections details with props & schemas ; yaml
;; preconsider layout stuff too, either here or in sitemap
out : ["uxdatamap"]
*/
/*
- not sure if needs uxsitemap structure etc or just the uxdatamap structure (and other analysis docs)
- should also consider shared views and their distribution etc, unless that is done in uxsitemap
that and cross links ... unless that too in uxsitemap
- focus here is data not other stuff
*/
const { uxdatamap, uxsitemap } = data;
/*
uxdatamap: { structure : { root{} , routes{} } }
uxsitemap: { structure : { views{ unique{}, shared{} } , crosslinks[{source,target,intent,action}] } }
-> needs parallel chunking because high detail on each
-> parallel chunk uxsitemap views to detail data ops on them and their sections
-> all shared global views GV_* in same chunk (because diff approach?) , unique views uv_* in multi chunks because numerous
*/
let tasks = [];
const UVs = Object.keys(uxsitemap.structure.views.unique);
if (UVs.length) {
_chunkify(UVs, 5).map((uniqueViewsIdsChunk) => {
let filteredUxSitemap = { views: { unique: {} } };
uniqueViewsIdsChunk.map((uv) => {
filteredUxSitemap.views.unique[uv] = uxsitemap.structure.views.unique[uv];
});
tasks.push({
uxsitemap: filteredUxSitemap, // filtered ux sitemap with all chunk of unique views
crosslinks: uxsitemap.structure.crosslinks.filter((crosslink) => {
return uniqueViewsIdsChunk.includes(crosslink.source);
}),
ids: uniqueViewsIdsChunk,
type: `unique`,
});
});
}
const GVs = Object.keys(uxsitemap.structure.views.shared);
if (GVs.length) {
tasks.push({
uxsitemap: { views: { shared: uxsitemap.structure.views.shared } }, // filtered ux sitemap with all shared views
crosslinks: uxsitemap.structure.crosslinks.filter((crosslink) => {
return GVs.includes(crosslink.source);
}),
ids: GVs,
type: `shared`,
});
}
let views = {};
await Promise.all(
tasks.map(async (task) => {
const response = await context.run({
id: `UX:DATAMAP::VIEWS:CHUNK`,
context,
data: { ...data, task },
});
views = merge(views, response.views);
}),
);
// console.dir({ __debug_uxDatamapViews: {views} } , {depth:null})
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "architecture:uxdatamap:views",
},
type: `end`,
content: {
key: `uxdatamap.views`,
data: views,
},
},
});
return {
uxdatamap: {
...uxdatamap,
views,
},
};
}
async function uxDatamapViewsChunk({ context, data }) {
/* ;; UX:DATAMAP::VIEWS:CHUNK
chunk processor for views+sections detailing
out : ["views"] # make sure later, maybe there's more to it ?
*/
/*
- not sure if needs uxsitemap structure etc or just the uxdatamap structure (and other analysis docs)
- should also consider shared views and their distribution etc, unless that is done in uxsitemap
that and cross links ... unless that too in uxsitemap
- focus here is data not other stuff ! can link through filtering with uxsitemap later
*/
const { pm, uxdatamap, backend, task } = data;
const { prd, frd, brd, uxsmd, uxdmd } = pm;
/*
--> task : {
uxsitemap{
views{
unique{ __chunk of views__ },
shared{ __chunk of views__ },
},
}
crosslinks[],
ids[ ids of views__ ],
type: unique || shared
}
// returns {views{ unique{[id]:...} , shared{[id]:...} }}
*/
const messages = [
{
role: "system",
content: `- you are a genius Product Manager & App Architect
- your role is to detail the frontend app architecture structure for the provided project,
for the specific views with ids : ${task.ids.join(",")},
based on the provided task and analysis documents
- your answer should be in the strict provided format that will be defined further
your aim is to determine the:
* the structure of the specified frontend views (views ${task.ids.join(",")} ) ,
for each view :
* state variables , schemas , dynamic data
* what it receives from the route (slugs)
* what it receives in URL params
* action / functions in this view and how they come into play to cover all intended features of the view
- for each view , ask yourself:
* what are the features involved in this view ; and how they come into play in app's features / journeys ?
* what data does this view receive as route slugs and url params ?
* what are all the state variables / actions / functions / ... required by features expected to be seen by users in the frontend ?
- your detailed view structure for each view will be used to make a prod-ready app architecture and will be responsible for an app used by thousands of users
- your aim is to cover all use cases, as the expert product manager & architect you are
> your answer is required to be in this strict defined format, in this strict order, in a strictly parseable YAML :
\`\`\`yaml
# use view ids directly under the views object ; will either be UV_* (unique views) or GV_* (shared global views) ;
# for all provided views ids in task, conduct the structure detailing
views:
[view id]: # the view id that is detailed ; should be a value from : ${task.ids.join(" , ")}
slugs?: # if view takes dynamic slug variable (defined in route in app structure), describe
- name: "..." # slug id as defined in route
intent: "..." # consise one sentence description of the slug role
required: boolean # if required, set to true
default: "..." # default init value for the slug
...
urlParams?: # if view takes URL params (defined in app structure), describe
- name: "..." # URL param key as defined in app structure
intent: "..." # consise one sentence description of the slug role
required: boolean # if required, set to true
...
stateVariables?: # if view is stateful and needs view-level state variables, describe ;
- name: "..." # variable name
role: "..." # describe
schema: # variable schema in JS-parseable interface schema format ; schema should be fully defined including nested fields
default: # default init value for the view's state variables
mappingIfFromSource?: # if this state variable is set based on : received route slugs , or URL params , or app global state , specify
- source: # is either "slugs" || "urlParams" || "globalAppState"
name: # variable name as defined in slugs / urlParams / globalAppState to link it
...
...
actions?: # if view has dynamic actions/functions, describe
- name: "..." # action/function name
intent: "..." # describe
triggers: # list of ways the action/function is triggered; can be multiple ; ie. on page load, when some button is clicked inside view, when some state variable value changes, etc ...
interactionWithBackend?: # if action interacts with backend, describe
description: "if applies , describe the interaction with backend ; also mention if calls backend api or realtime, and describe how ; be detailed"
...
globalStateVariablesAccessed?: # if view needs to access global state variables (as defined in provided app structure under root.globalState), specify those in this object ; object should also contain description of relationship (ie. 'to get auth token to use in api calls authorization header' , 'to get current user profile to prefill [...] ' , etc ... )
[...]
\`\`\`
---
note :
- for any field that requires making example, you can draw from provided data examples in provided task docs
for any field such as image, media ... make sure you use urls rather than local references ;
if some entry requires an image url or media, use a valid "https://picsum.photos/..." url for it !
---
for yaml to be 100% valid, use quotes around string as much as possible
your reply should start with : "\`\`\`yaml" and end with "\`\`\`"
you will be tipped $99999 + major company shares`,
},
{
role: "user",
content: `\`\`\`PRD:app-product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:app-features-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`UXSMD:ux-sitemap-document
${uxsmd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`UXDMD:ux-sitemap-data-crossanalysis-document
${uxdmd}
\`\`\``,
},
{
role: "user",
content:
`\`\`\`BRD:backend-requirements-document
${brd}
\`\`\`
` +
(!backend?.requirements?.restApi?.required
? ""
: `---
\`\`\`BACKEND:specifications:openAPI
${yaml.stringify(backend.specifications.openapi)}
\`\`\`
`) +
(!backend?.requirements?.realtimeWebsockets?.required
? ""
: `---
\`\`\`BACKEND:specifications:asyncAPI
${yaml.stringify(backend.specifications.asyncapi)}
\`\`\`
` +
`
---
\`\`\`BRD:server:main
${yaml.stringify(backend.server.main)}
\`\`\`
`),
},
{
role: "user",
content: `\`\`\`UX:ux-datamap
${yaml.stringify(uxdatamap.structure)}
\`\`\``,
},
{
role: "user",
content: `\`\`\`UX:ux-sitemap-distilled
${yaml.stringify(task.uxsitemap)}
\`\`\``,
},
{
role: "user",
content: `make the detailed architecture for views ids : ${task.ids.join(",")} and their components.
only make the detailed architecture for views ids : ${task.ids.join(",")} ; not any other views,
using the provided instructions and format
make a coherent, cohesive, perfect, detailed structure
answer in parseable YAML format, strictly in the provided instructions format ; strictly parseable YAML ;
you're a genius`,
},
];
const views = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`chatgpt-4o-latest`, // `chatgpt-4o-latest`,//`gpt-4o`,
messages,
preparser: `backticks`,
parser: `yaml`,
},
})
).generated.views;
return {
views: {
[task.type]: views,
},
}; // -> views : { unique{[ids...]} , shared{ids[...]} }
}
export default {
"UX:DATAMAP::STRUCTURE": uxDatamapStructure,
"UX:DATAMAP::VIEWS": uxDatamapViews,
"UX:DATAMAP::VIEWS:CHUNK": uxDatamapViewsChunk,
};

View File

@@ -0,0 +1,238 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function uxSitemapStructure({ context, data }) {
/* generate uxsitemap in strict format */
const { pm } = data;
const { prd, frd, uxsmd } = pm;
const messages = [
{
role: "system",
content: `You are an extremely experienced UX expert and software product manager.
Your role is to create a comprehensive UX sitemap from the provided information.
- Think very slowly and thoroughly. Take a deep breath.
- Provide a comprehensive, well-thought-out reply that covers all aspects of the analyzed problem.
- You are an expert at what you do.
- You are known to never forget a single angle.
- You will be tipped $999 for each perfect reply.
Answer in a strict parseable YAML format, in this format:
\`\`\`yaml
# ux sitemap structure in great details
uxsitemap:
views:
uniqueViews: # unique views with ids UV_* , as specified in provided docs
[unique view id UV_*]:
title: ""
extendedDescription: "describe the view in great extended detail that covers every single thing that should go in it without any omittance" # essential to detail specifics ! dont assume someone knows what you mean, detail it in details !
notes: "important notes regarding this view component or its state(s) that were mentionned in provided docs & analysis and that should be mentionned"
role: "describe in detail role of this view in the app ; namely the features it aims to satisfy within the app features and UX"
globalSharedViews: # global shared views with ids GV_* such as nav etc, as specified in provided docs
[global shared view id GV_*]:
title: ""
extendedDescription: "describe the shared view in great extended detail that covers every single thing that should go in it without any omittance" # essential to detail specifics ! dont assume someone knows what you mean, detail it in details !
notes: "important notes regarding view component or its state(s) that were mentionned in provided docs & analysis and that should be mentionned"
role: "describe in detail role of this view in the app ; namely the features it aims to satisfy within the app features and UX"
sharedByViews: [] # list of ids of all unique views UV_* that have this shared view displayed alongside with them
relativePosition: "" # describe the relative positioning of this GV_* shared view in relation to the app layout and unique views it is shared with;
[...]
# cross inter-app links relationships between views
crossLinks:
- sourceViewId: "" # UV_* or GV_*
targetViewId: "" # UV_*
intent: ""
actionDescription: ""
[...]
\`\`\`
---
- every view id you refer to must exist in provided docs !
- As the expert, you should make a complete and comprehensive UX sitemap,
including all parts that might be unemphasized by a less experienced UX worker, if required by the app of course, such as auth flows, terms, etc.
your reply should start with : "\`\`\`yaml" and end with "\`\`\`"
for yaml to be 100% valid, use quotes around string as much as possible
A comprehensive UX sitemap in the provided yaml format
You are a genius at this task.`,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`FRD:features-requirements-document
${frd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`UXSMD:ux-sitemap-analysis-document
${uxsmd}
\`\`\``,
},
{
role: "user",
content: `Make a full, comprehensive UX sitemap for it
You're a genius do a great job`,
},
];
const uxsitemapStructure = (
await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, // `chatgpt-4o-latest`,//`gpt-4o`,
messages,
preparser: `backticks`,
parser: `yaml`,
},
})
).generated.uxsitemap;
// <----- do post processing to format the response
const uxsitemap = {
structure: {
views: {
unique: uxsitemapStructure.views.uniqueViews,
shared: uxsitemapStructure.views.globalSharedViews,
},
crosslinks: uxsitemapStructure.crossLinks.map((link) => {
return {
source: link.sourceViewId,
target: link.targetViewId,
intent: link.intent,
action: link.actionDescription,
};
}),
},
};
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "architecture:uxsitemap:structure",
},
type: `end`,
content: {
key: "uxsitemap.structure",
data: uxsitemap.structure,
},
},
});
return {
uxsitemap,
};
}
// ____________________________________________________________________________________________________
async function uxSitemapViews({ context, data }) {
/* ;; UX:SITEMAP::VIEWS
{pm docs , db , openapi?, UXSMD, uxsitemap{structure} } -> uxsitemap{...,views}
out : ["uxsitemap"]
*/
// distribute processing of views to submodules , might typically replace ie. in case of specialized and whatnot
// but serves as a refiner , not as a detailer
// so can just pass for now
await Promise.all();
// postprocess to return single coherent object
return {};
}
// ____________________________________________________________________________________________________
async function uxSitemapViewsNormal({ context, data }) {
/* ;; UX:SITEMAP::VIEWS:NORMAL
chunk processing from UX:SITEMAP::VIEWS ; for normal views
out : ["views"]
*/
const messages = [
{
role: "system",
content: "[system+format]",
},
];
await context.run({
id: `op:LLM::GEN`,
context,
data: { messages, preparser: false, parser: false },
});
return {};
}
async function uxSitemapViewsSpecial({ context, data }) {
/* ;; UX:SITEMAP::VIEWS:SPECIAL
chunk processing from UX:SITEMAP::VIEWS; specialized processors for special sections ; ie. landing would be based on some highconversion process etc;
might override provided sections descriptions
out : ["views"]
*/
const messages = [
{
role: "system",
content: "[system+format]",
},
];
await context.run({
id: `op:LLM::GEN`,
context,
data: { messages, preparser: false, parser: false },
});
return {};
}
async function uxSitemapViewsShared({ context, data }) {
/* ;; UX:SITEMAP::VIEWS:SHARED
chunk processing from UX:SITEMAP::VIEWS ; for shared views implementations
out : ["views"]
*/
const messages = [
{
role: "system",
content: "[system+format]",
},
];
await context.run({
id: `op:LLM::GEN`,
context,
data: { messages, preparser: false, parser: false },
});
return {};
}
export default {
"UX:SITEMAP::STRUCTURE": uxSitemapStructure,
"UX:SITEMAP::VIEWS": uxSitemapViews,
"UX:SITEMAP::VIEWS:NORMAL": uxSitemapViewsNormal,
"UX:SITEMAP::VIEWS:SPECIAL": uxSitemapViewsSpecial,
"UX:SITEMAP::VIEWS:SHARED": uxSitemapViewsShared,
};

View File

@@ -0,0 +1,264 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function promptRoot({ context, data }) {
// have a placeholder redux store module in case it'd wrap with non implemented store
/*
better implement using prompt, provide ux sitemap & datamap
provide react (redux store) too, in prompt also, for auth restricted stuff
*/
const { uxsitemap, uxdatamap, webapp } = data;
const viewsImportHead = [
...Object.keys(uxsitemap.structure.views.shared),
...Object.keys(uxsitemap.structure.views.unique),
]
.map((viewId) => {
return `import ${viewId} from '@/components/views/${viewId}.tsx';`;
})
.join("\n");
const boilerplate = `import React, { useState, useEffect } from "react";
import "./App.css";
import {
Route,
Routes,
} from "react-router-dom";
/*
import views : unique views (UV_*) and shared global views (GV_*)
*/
import UV_ExampleLanding from '@/components/views/UV_ExampleLanding.tsx';
import UV_OtherViewExample from '@/components/views/UV_OtherViewExample.tsx';
import GV_NavTop from '@/components/views/GV_NavTop.tsx';
import GV_Footer from '@/components/views/GV_Footer.tsx';
const App: React.FC = () => {
return (
<>
<GV_NavTop />
<Routes>
<Route path="/" element={<UV_ExampleLanding />} />
<Route path="/find/:slugexample" element={<UV_OtherViewExample/>} />
</Routes>
<GV_Footer />
</>
);
};
export default App;
`;
/*
x emphasize redux / auth stuff
x provide example of reactrouterdom structure ; whole thing
x emphasize relative position of shared components ; thus emphasize tailwind usage and styling in rel to shared components
x emphasize React FC
x do not assume ! prompt
*/
return [
{
role: `system`,
content: `your role as an expert web app and react senior dev and product manager is to write the code for the root react + tailwind app (App.tsx) component component based on the provided task
> ask yourself what should be defined in the root App component in terms of:
> paths & unique views
> global shared views, and their relative position and conditionals
> auth related restriction (if applies) in relation to the store provider that wraps the App component you are writing here ( it's used like this : \`<Provider store={store}> <App /> </Provider>\` )
> very important :
do not auth restrict an entire view just because some sections of it are auth restricted while other elements are not auth restricted !! think sloowly !
> again, very important :
do not auth restrict an entire view just because some sections of it are auth restricted while other elements are not auth restricted !! which would mess things up ! think sloowly !
> your answer should strictly be the code for the App.tsx component
your answer will be directly pasted into the component
> it should encompasses everything required by the app's App, in one single script
> the store script you will write will wrap the root component of the app ; no need to write the wrapper part ; it will be included later as \`<Provider store={store}> <App/> </Provider>\` , where the <App/> is the actual script your will write and export here
---
your code should import the provided and described views, as follows :
\`\`\`
/* ... */
${viewsImportHead}
/* ... */
\`\`\`
---
> conduct the analysis first, reply iwith the analysis inside of \`\`\`markdown\`\`\`
> then, answer with component code in \`\`\`tsx\`\`\` based on your analysis
you are a genius + you get $9999`,
},
{
role: "user",
content: `\`\`\`app:uxsitemap
${yaml.stringify({
structure: {
views: uxsitemap.structure.views,
},
})}
\`\`\``,
},
{
role: "user",
content: `\`\`\`app:app-structure
${yaml.stringify({
structure: uxdatamap.structure.routes,
})}
\`\`\``,
},
{
role: `user`,
content: `an example of the overall root App structure is meant to be is as follows ; use it as a reference :
\`\`\`tsx
${boilerplate}
\`\`\`
---
for additional reference if needed (ie. in case of auth conditionals)
the code for the global state store component that wraps the app (including this view you're working on) is defined in the following ;
you can import the store exports if needed by using : \`import {...} from '@/store/main'\`
\`\`\`@/store/main.tsx
${webapp.react.store.redux.latest.tsx}
\`\`\`
`,
},
{
role: "user",
content: `make the analysis and implement the tsx component;
> implement the react+tailwind component, fully and working from the get go;
> you are implementing the tsx code for the root App component
---
your code should import the provided and described views, as follows :
\`\`\`
/* ... */
${viewsImportHead}
/* ... */
\`\`\`
---
> should be React.FC ! important !
> you should respect the way to build Routes in the provided code snippet ! do not innovate in this regard !
for reminder, this is the way :
\`\`\`
import {
Route,
Routes,
} from "react-router-dom";
[...]
<Routes>
<Route path="/" element={<UV_ExampleLanding />} />
<Route path="/find/:slugexample" element={<UV_OtherViewExample/>} />
</Routes>
[...]
\`\`\`
---
> do not hallucinate methods or component imports that do not exist !
all that exists has been provided to you
any required additional actions should be implemented by you ; you are provided with all needed details to implement anything !
> the global store and its methods is defined in @/store/main.tsx
> the views are defined in @/components/views/[sectionId].tsx
> that's all !!
DO NOT ASSUME OTHER STUFF IS IMPLEMENTED !
IF YOU NEED TO CALL THE API OR SOMETHING SIMILAR, WRITE YOUR OWN FUNCTIONS INSIDE THIS VIEW !!
IMPLEMENT, DO NOT ASSUME ANYTHING ELSE IS IMPLEMENTED !
> conduct the analysis first, reply with the analysis inside of \`\`\`markdown\`\`\`
it should emphasize the full functionalities required and specified in the provided details
> then, answer in a react tsx code for the App root component reply in \`\`\`tsx\`\`\` based on your analysis
the code should be complete and fully functional !
you are a genius + you get $9999`,
},
];
}
async function webappRootGenerate({ context, data }) {
const timestamp = `${Date.now()}`;
const messages = await promptRoot({ context, data });
const { generated } = await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages: messages,
preparser: false,
parser: false,
},
});
const extraction = await utils.parsers.extract.backticksMultiple({
text: generated,
delimiters: [`markdown`, `tsx`],
});
const { markdown, tsx } = extraction;
if (!tsx.length) {
throw new Error("webapp:root:generate error - generated tsx is empty");
}
const generatedRoot = {
analysis: markdown,
tsx,
timestamp,
};
await Promise.all(
[`${timestamp}`, `latest`].map(async (version) => {
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: `webapp:react:root`,
refs: {
id: "app",
version,
},
},
type: `end`,
content: {
key: `webapp.react.root.app.${version}`,
data: generatedRoot,
},
},
});
}),
);
return {
timestamp,
webapp: {
react: {
root: {
// ie. "views" , "sections" , "store" , "root"
app: {
// ie. {UV_* , SEC_* , redux} , "app" (in case of root)
[timestamp]: generatedRoot,
latest: generatedRoot,
},
},
},
},
};
}
export default {
"WEBAPP:ROOT::GENERATE": webappRootGenerate,
};

View File

@@ -0,0 +1,291 @@
import utils from "@/utils/index.js";
import yaml from "yaml";
async function promptStore({ context, data }) {
const { pm, db, backend, uxdatamap } = data;
const { prd, uxdmd, brd } = pm;
const store = { id: "redux" };
/*
[system]
*/
return [
{
role: `system`,
content: `your role as an expert web app and react senior dev and product manager is to write the code for the ${store.id} store script component based on the provided task; which encompasses all required data states and methods for the app's global states and actions
---
- analysis , in between \`\`\`markdown\`\`\`\` section
- full store component tsx code , in between \`\`\`tsx\`\`\`\` section
- dependencies, in between \`\`\`yaml\`\`\`\` section ; where any needed packages imported into the component code and need to be installed will be mentionned ; the yaml should have object : {dependencies : {"package":"version"} } ; (you can also just put "*" for version)
use doublequotes for every string inside the yaml to make sure formatting is good
---
> ask yourself what should be defined in the store component that will be used by all views later , in terms of global state variables and actions
> your answer should strictly be the code for the store tsx component
your answer will be directly pasted into the component
> it should encompasses everything required by the app's global store states and actions, in one single script
> the store script you will write will wrap the root component of the app ; no need to write the wrapper part ; it will be included later as \`<Provider store={store}> <App/> </Provider>\` , where the store is the actual script your will write and export here
---
try to use async/await when you can
> extremely turbo important :
- you can only use the following packages :
- @reduxjs/toolkit
- react-redux
- redux-persist
- socket.io-client
- axios
- you need to export default and make sure everything else that will be needed by views is exported too !
---
note :
> if app has auth capabilities, make sure you global state covers auth token
> if app has realtime capabilities, make sure global state covers realtime auth and subscriptions
feel free to consult the provided backend server code to help you figure out how those details should be implemented
---
> important :
the store should strictly handle getting and setting the provided global state variables !
it should not handle making the other api calls - those parts will be handled by concerned components !
> again , very important :
the store should strictly handle getting and setting the provided global state variables !
it should not handle making the other api calls - those parts will be handled by concerned components !
> super important :
use localstorage to avoid things being lost on refresh !
---
> conduct the analysis first, reply iwith the analysis inside of \`\`\`markdown\`\`\`
> make full complete store component code in \`\`\`tsx\`\`\` based on your analysis
> dependencies, in between \`\`\`yaml\`\`\`\` with object: {dependencies : {package:version}}
you are a genius + you get $9999`,
},
{
role: "user",
content: `\`\`\`PRD:product-requirements-document
${prd}
\`\`\``,
},
{
role: "user",
content: `\`\`\`UX-analysis-document
${uxdmd}
\`\`\``,
},
{
role: "user",
content:
`\`\`\`BRD:backend-requirements-document
${brd}
\`\`\`
` +
(!backend?.requirements?.restApi?.required
? ""
: `---
\`\`\`BACKEND:specifications:openAPI
${yaml.stringify(backend.specifications.openapi)}
\`\`\`
`) +
(!backend?.requirements?.realtimeWebsockets?.required
? ""
: `---
\`\`\`BACKEND:specifications:asyncAPI
${yaml.stringify(backend.specifications.asyncapi)}
\`\`\`
` +
`
---
\`\`\`BRD:server:main
${yaml.stringify(backend.server.main)}
\`\`\`
`),
},
{
role: "user",
content: `\`\`\`app:architecture
${yaml.stringify(uxdatamap)}
\`\`\``,
},
{
role: "user",
content: `make the analysis and implement the tsx component;
> implement the ${store.id} store component, fully and working from the get go;
---
try to use async/await when you can
> extremely turbo important !!! :
- you can only use the following packages :
- @reduxjs/toolkit
- react-redux
- redux-persist
- socket.io-client
- axios
- you need to export default and make sure everything else that will be needed by views is exported too !
---
> make sure it has all the required imports !! no missing imports !
> should export a default method too ! so that it can be imported later as \`import store from '@/store/main'\` !
> important :
the store should strictly:
> handle getting and setting the provided global state variables !
> if applies , handle realtime events subscriptions
it should not handle making view-specific api calls - those parts will be handled by concerned view components !
> again, important :
the store should strictly:
> handle getting and setting the provided global state variables !
> if applies , handle realtime events subscriptions
it should not handle making view-specific api calls - those parts will be handled by concerned view components !
> super important :
use localstorage to avoid things being lost on refresh !
> do not assume that anything else is implemented !
> do not make any assumptions that something else will be plugged here !
> implement 100% of everything you need to implement ! do not hallucinate importing something that doesnt exist!
> the store component should work 100% out the box without any further edits ! very important !
---
important :
> use snake_case for any naming you do
extremely important :
> ensure full perfect coherence with: backend server methods / events / names, schemas
> field names and schemas epecially
---
- analysis , in between \`\`\`markdown\`\`\`\` section
- full store component tsx code , in between \`\`\`tsx\`\`\`\` section
- dependencies, with object {dependencies:{package:version,...}}, in between \`\`\`yaml\`\`\`\` section
you are a genius + you get $9999`,
},
];
}
async function webappStoreGenerate({ context, data }) {
const timestamp = `${Date.now()}`;
const messages = await promptStore({ context, data });
const { generated } = await context.run({
id: "op:LLM::GEN",
context,
data: {
model: `chatgpt-4o-latest`, //`gpt-4o`,
messages: messages,
preparser: false,
parser: false,
},
});
const extraction = await utils.parsers.extract.backticksMultiple({
text: generated,
delimiters: [`markdown`, `tsx`, `yaml`],
});
const { markdown, tsx } = extraction;
if (!tsx.length) {
throw new Error("webapp:store:generate error - generated tsx is empty");
}
const parsedYaml = extraction.yaml ? yaml.parse(extraction.yaml) : {};
const generatedStore = {
analysis: markdown,
tsx,
dependencies: parsedYaml.dependencies
? Object.fromEntries(
Object.keys(parsedYaml.dependencies).map((key) => [key, "*"]),
)
: [],
timestamp,
};
await Promise.all(
[`${timestamp}`, `latest`].map(async (version) => {
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: `webapp:react:store`,
refs: {
id: "redux",
version,
},
},
type: `end`,
content: {
key: `webapp.react.store.redux.${version}`,
data: generatedStore,
},
},
});
}),
);
if (Object.keys(generatedStore.dependencies).length) {
await context.run({
id: "op:PROJECT::STATE:UPDATE",
context,
data: {
operation: {
id: "settings:config:package",
},
type: `end`,
content: {
key: "settings.config.package",
data: {
webapp: {
dependencies: generatedStore.dependencies,
},
},
},
},
});
}
return {
timestamp,
webapp: {
react: {
store: {
// ie. "views" , "sections" , "store" , "root"
redux: {
// ie. {UV_* , SEC_* , redux} , "app" (in case of root)
[timestamp]: generatedStore,
latest: generatedStore,
},
},
},
},
};
}
export default {
"WEBAPP:STORE::GENERATE": webappStoreGenerate,
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
## Notes
This is a demo design system and will be replaced on official post-alpha release
## Credits
Renders dumped from Figma Presets:
- Blocks.pm by Hexa Plugin
- Google Material & Figma Core Design systems

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

View File

@@ -0,0 +1,73 @@
primitives:
- id: heading
description: A primary heading for sectional content
- id: subheading
description: A secondary heading for a subsection of content
- id: text_line
description: A single line of text
- id: text_paragraph
description: A block of text longer than a line
- id: button
description: A clickable element used to perform actions
stretch: true
- id: link
description: A hyperlink pointing to another resource
- id: tag
description: An small capsule for categorizing or labeling - can also be used as a small status indicator or be clickable
- id: avatar
description: A graphical representation of either a user or brand, typically a photo or icon
- id: image
description: An element to display pictures or graphics
stretch: true
- id: icon
description: A graphical representation of an idea, action, or object
- id: input_datepicker
stretch: true
description: A control allowing the user to select a specific date
- id: input_description
stretch: true
description: An informational text describing an input field
- id: input_field
stretch: true
description: An input area where the user can enter text
- id: input_label
description: A label associated with an input field to describe its purpose
- id: input_searchfield
stretch: true
description: An input field specifically for search queries
- id: input_select
stretch: true
description: A dropdown menu allowing the user to choose from a list of options
- id: input_textarea
stretch: true
description: An input field for entering multi-line text
- id: radio_button
description: A control allowing the user to select one option from a group
- id: checkbox
description: A control that allows the user to select or deselect an option
- id: switch
description: A control allowing the user to toggle between two states
- id: slider
description: A control for selecting a value from a range
- id: media
description: An element for embedding video or audio
stretch: true
- id: map
description: A graphical representation of geographical information
stretch: true
- id: badge
description: A round indicator with a number inside it, used for example for counting or tracking
- id: calendar
description: A graphical representation of a calendar
stretch: true
- id: code_block
description: A block for displaying formatted code
stretch: true
- id: button_fab
description: A floating action round button that is sticky and fixed to the bottom right corner of the page
- id: progress_bar
description: A horizontal bar indicating progress toward completion
stretch: true
- id: nonprimitive
description: A placeholder for non-primitive components that should be designed based on description
stretch: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1,70 @@
Name : Accordion
Description : A vertically stacked set of interactive headings that each reveal a section of content.
---
### import
```
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
```
---
### use
```accordion.mdx
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger>Is it accessible?</AccordionTrigger>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design pattern.
</AccordionContent>
</AccordionItem>
</Accordion>
```
---
### examples
```accordion-demo.tsx
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
export default function AccordionDemo() {
return (
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="item-1">
<AccordionTrigger>Is it accessible?</AccordionTrigger>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design pattern.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2">
<AccordionTrigger>Is it styled?</AccordionTrigger>
<AccordionContent>
Yes. It comes with default styles that matches the other
components&apos; aesthetic.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3">
<AccordionTrigger>Is it animated?</AccordionTrigger>
<AccordionContent>
Yes. It&apos;s animated by default, but you can disable it if you
prefer.
</AccordionContent>
</AccordionItem>
</Accordion>
)
}
```

View File

@@ -0,0 +1,42 @@
Name : Avatar
Description : An image element with a fallback for representing the user.
---
### import
```
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
```
---
### use
```avatar.mdx
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
```
---
### examples
```avatar-demo.tsx
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar"
export default function AvatarDemo() {
return (
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
)
}
```

View File

@@ -0,0 +1,59 @@
Name : Badge
Description : Displays a badge or a component that looks like a badge.
---
### import
```
import { Badge } from "@/components/ui/badge"
```
---
### use
```badge.mdx
<Badge variant="outline">Badge</Badge>
```
```badge.mdx
import { badgeVariants } from "@/components/ui/badge"
<Link className={badgeVariants({ variant: "outline" })}>Badge</Link>
```
---
### examples
```badge-demo.tsx
import { Badge } from "@/components/ui/badge"
export default function BadgeDemo() {
return <Badge>Badge</Badge>
}
```
```badge-destructive.tsx
import { Badge } from "@/components/ui/badge"
export default function BadgeDestructive() {
return <Badge variant="destructive">Destructive</Badge>
}
```
```badge-outline.tsx
import { Badge } from "@/components/ui/badge"
export default function BadgeOutline() {
return <Badge variant="outline">Outline</Badge>
}
```
```badge-secondary.tsx
import { Badge } from "@/components/ui/badge"
export default function BadgeSecondary() {
return <Badge variant="secondary">Secondary</Badge>
}
```

View File

@@ -0,0 +1,41 @@
Name : Progress
Description : Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.
---
### import
```
import { Progress } from "@/components/ui/progress"
```
---
### use
```progress.mdx
<Progress value={33} />
```
---
### examples
```progress-demo.tsx
"use client"
import * as React from "react"
import { Progress } from "@/components/ui/progress"
export default function ProgressDemo() {
const [progress, setProgress] = React.useState(13)
React.useEffect(() => {
const timer = setTimeout(() => setProgress(66), 500)
return () => clearTimeout(timer)
}, [])
return <Progress value={progress} className="w-[60%]" />
}
```

View File

@@ -0,0 +1,41 @@
Name : Slider
Description : An input where the user selects a value from within a given range.
---
### import
```
import { Slider } from "@/components/ui/slider"
```
---
### use
```slider.mdx
<Slider defaultValue={[33]} max={100} step={1} />
```
---
### examples
```slider-demo.tsx
import { cn } from "@/lib/utils"
import { Slider } from "@/components/ui/slider"
type SliderProps = React.ComponentProps<typeof Slider>
export default function SliderDemo({ className, ...props }: SliderProps) {
return (
<Slider
defaultValue={[50]}
max={100}
step={1}
className={cn("w-[60%]", className)}
{...props}
/>
)
}
```

View File

@@ -0,0 +1,62 @@
---
title: Breadcrumb
description: Displays the path to the current resource using a hierarchy of links.
component: true
---
## Usage
```tsx
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
```
```tsx
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="/components">Components</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
```
## Examples
### Custom separator
Use a custom component as `children` for `<BreadcrumbSeparator />` to create a custom separator.
```tsx
import { Slash } from "lucide-react"
...
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator>
<Slash />
</BreadcrumbSeparator>
<BreadcrumbItem>
<BreadcrumbLink href="/components">Components</BreadcrumbLink>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
```

View File

@@ -0,0 +1,124 @@
Name : Button
Description : Displays a button or a component that looks like a button.
---
### import
```
import { Button } from "@/components/ui/button"
```
---
### use
```button.mdx
import { Button } from "@/components/ui/button"
<Button variant="outline">Button</Button>
```
```button.mdx
import { Link } from 'react-router-dom';
import { Button } from "@/components/ui/button"
...
<Link to="/">
<Button variant="outline">Button</Button>
</Link>
```
---
### examples
```button-demo.tsx
import { Button } from "@/components/ui/button"
export default function ButtonDemo() {
return <Button>Button</Button>
}
```
```button-destructive.tsx
import { Button } from "@/components/ui/button"
export default function ButtonDestructive() {
return <Button variant="destructive">Destructive</Button>
}
```
```button-ghost.tsx
import { Button } from "@/components/ui/button"
export default function ButtonGhost() {
return <Button variant="ghost">Ghost</Button>
}
```
```button-icon.tsx
import { ChevronRight } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonIcon() {
return (
<Button variant="outline" size="icon">
<ChevronRight className="h-4 w-4" />
</Button>
)
}
```
```button-link.tsx
import { Button } from "@/components/ui/button"
export default function ButtonLink() {
return <Button variant="link">Link</Button>
}
```
```button-loading.tsx
import { Loader2 } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonLoading() {
return (
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Please wait
</Button>
)
}
```
```button-outline.tsx
import { Button } from "@/components/ui/button"
export default function ButtonOutline() {
return <Button variant="outline">Outline</Button>
}
```
```button-secondary.tsx
import { Button } from "@/components/ui/button"
export default function ButtonSecondary() {
return <Button variant="secondary">Secondary</Button>
}
```
```button-with-icon.tsx
import { Mail } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonWithIcon() {
return (
<Button>
<Mail className="mr-2 h-4 w-4" /> Login with Email
</Button>
)
}
```

View File

@@ -0,0 +1,124 @@
Name : Button
Description : Displays a button or a component that looks like a button.
---
### import
```
import { Button } from "@/components/ui/button"
```
---
### use
```button.mdx
import { Button } from "@/components/ui/button"
<Button variant="outline">Button</Button>
```
```button.mdx
import { Link } from 'react-router-dom';
import { Button } from "@/components/ui/button"
...
<Link to="/">
<Button variant="outline">Button</Button>
</Link>
```
---
### examples
```button-demo.tsx
import { Button } from "@/components/ui/button"
export default function ButtonDemo() {
return <Button>Button</Button>
}
```
```button-destructive.tsx
import { Button } from "@/components/ui/button"
export default function ButtonDestructive() {
return <Button variant="destructive">Destructive</Button>
}
```
```button-ghost.tsx
import { Button } from "@/components/ui/button"
export default function ButtonGhost() {
return <Button variant="ghost">Ghost</Button>
}
```
```button-icon.tsx
import { ChevronRight } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonIcon() {
return (
<Button variant="outline" size="icon">
<ChevronRight className="h-4 w-4" />
</Button>
)
}
```
```button-link.tsx
import { Button } from "@/components/ui/button"
export default function ButtonLink() {
return <Button variant="link">Link</Button>
}
```
```button-loading.tsx
import { Loader2 } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonLoading() {
return (
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Please wait
</Button>
)
}
```
```button-outline.tsx
import { Button } from "@/components/ui/button"
export default function ButtonOutline() {
return <Button variant="outline">Outline</Button>
}
```
```button-secondary.tsx
import { Button } from "@/components/ui/button"
export default function ButtonSecondary() {
return <Button variant="secondary">Secondary</Button>
}
```
```button-with-icon.tsx
import { Mail } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonWithIcon() {
return (
<Button>
<Mail className="mr-2 h-4 w-4" /> Login with Email
</Button>
)
}
```

View File

@@ -0,0 +1,124 @@
Name : Button
Description : Displays a button or a component that looks like a button.
---
### import
```
import { Button } from "@/components/ui/button"
```
---
### use
```button.mdx
import { Button } from "@/components/ui/button"
<Button variant="outline">Button</Button>
```
```button.mdx
import { Link } from 'react-router-dom';
import { Button } from "@/components/ui/button"
...
<Link to="/">
<Button variant="outline">Button</Button>
</Link>
```
---
### examples
```button-demo.tsx
import { Button } from "@/components/ui/button"
export default function ButtonDemo() {
return <Button>Button</Button>
}
```
```button-destructive.tsx
import { Button } from "@/components/ui/button"
export default function ButtonDestructive() {
return <Button variant="destructive">Destructive</Button>
}
```
```button-ghost.tsx
import { Button } from "@/components/ui/button"
export default function ButtonGhost() {
return <Button variant="ghost">Ghost</Button>
}
```
```button-icon.tsx
import { ChevronRight } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonIcon() {
return (
<Button variant="outline" size="icon">
<ChevronRight className="h-4 w-4" />
</Button>
)
}
```
```button-link.tsx
import { Button } from "@/components/ui/button"
export default function ButtonLink() {
return <Button variant="link">Link</Button>
}
```
```button-loading.tsx
import { Loader2 } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonLoading() {
return (
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Please wait
</Button>
)
}
```
```button-outline.tsx
import { Button } from "@/components/ui/button"
export default function ButtonOutline() {
return <Button variant="outline">Outline</Button>
}
```
```button-secondary.tsx
import { Button } from "@/components/ui/button"
export default function ButtonSecondary() {
return <Button variant="secondary">Secondary</Button>
}
```
```button-with-icon.tsx
import { Mail } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonWithIcon() {
return (
<Button>
<Mail className="mr-2 h-4 w-4" /> Login with Email
</Button>
)
}
```

View File

@@ -0,0 +1,124 @@
Name : Button
Description : Displays a button or a component that looks like a button.
---
### import
```
import { Button } from "@/components/ui/button"
```
---
### use
```button.mdx
import { Button } from "@/components/ui/button"
<Button variant="outline">Button</Button>
```
```button.mdx
import { Link } from 'react-router-dom';
import { Button } from "@/components/ui/button"
...
<Link to="/">
<Button variant="outline">Button</Button>
</Link>
```
---
### examples
```button-demo.tsx
import { Button } from "@/components/ui/button"
export default function ButtonDemo() {
return <Button>Button</Button>
}
```
```button-destructive.tsx
import { Button } from "@/components/ui/button"
export default function ButtonDestructive() {
return <Button variant="destructive">Destructive</Button>
}
```
```button-ghost.tsx
import { Button } from "@/components/ui/button"
export default function ButtonGhost() {
return <Button variant="ghost">Ghost</Button>
}
```
```button-icon.tsx
import { ChevronRight } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonIcon() {
return (
<Button variant="outline" size="icon">
<ChevronRight className="h-4 w-4" />
</Button>
)
}
```
```button-link.tsx
import { Button } from "@/components/ui/button"
export default function ButtonLink() {
return <Button variant="link">Link</Button>
}
```
```button-loading.tsx
import { Loader2 } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonLoading() {
return (
<Button disabled>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Please wait
</Button>
)
}
```
```button-outline.tsx
import { Button } from "@/components/ui/button"
export default function ButtonOutline() {
return <Button variant="outline">Outline</Button>
}
```
```button-secondary.tsx
import { Button } from "@/components/ui/button"
export default function ButtonSecondary() {
return <Button variant="secondary">Secondary</Button>
}
```
```button-with-icon.tsx
import { Mail } from "lucide-react"
import { Button } from "@/components/ui/button"
export default function ButtonWithIcon() {
return (
<Button>
<Mail className="mr-2 h-4 w-4" /> Login with Email
</Button>
)
}
```

View File

@@ -0,0 +1,48 @@
Name : Calendar
Description : A date field component that allows users to enter and edit date.
---
### import
```
import { Calendar } from "@/components/ui/calendar"
```
---
### use
```calendar.mdx
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="rounded-md border"
/>
```
---
### examples
```calendar-demo.tsx
"use client"
import * as React from "react"
import { Calendar } from "@/components/ui/calendar"
export default function CalendarDemo() {
const [date, setDate] = React.useState<Date | undefined>(new Date())
return (
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="rounded-md border"
/>
)
}
```

View File

@@ -0,0 +1,220 @@
---
title: Carousel
description: A carousel with motion and swipe built using Embla.
---
## Usage
```tsx
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
```
```tsx
<Carousel>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
```
## Examples
### Sizes
To set the size of the items, you can use the `basis` utility class on the `<CarouselItem />`.
```tsx title="Example" showLineNumbers {4-6}
// 33% of the carousel width.
<Carousel>
<CarouselContent>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
```
```tsx title="Responsive" showLineNumbers {4-6}
// 50% on small screens and 33% on larger screens.
<Carousel>
<CarouselContent>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
```
### Spacing
To set the spacing between the items, we use a `pl-[VALUE]` utility on the `<CarouselItem />` and a negative `-ml-[VALUE]` on the `<CarouselContent />`.
<Callout className="mt-6">
**Why:** I tried to use the `gap` property or a `grid` layout on the `
<CarouselContent />` but it required a lot of math and mental effort to get the
spacing right. I found `pl-[VALUE]` and `-ml-[VALUE]` utilities much easier to
use.
You can always adjust this in your own project if you need to.
</Callout>
<ComponentPreview
name="carousel-spacing"
title="Carousel"
description="A carousel with 3 items with a spacing of 1rem."
/>
```tsx title="Example" showLineNumbers /-ml-4/ /pl-4/
<Carousel>
<CarouselContent className="-ml-4">
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
```
```tsx title="Responsive" showLineNumbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/
<Carousel>
<CarouselContent className="-ml-2 md:-ml-4">
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
```
### Orientation
Use the `orientation` prop to set the orientation of the carousel.
```tsx showLineNumbers /vertical | horizontal/
<Carousel orientation="vertical | horizontal">
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
```
## Options
You can pass options to the carousel using the `opts` prop.
```tsx showLineNumbers {2-5}
<Carousel
opts={{
align: "start",
loop: true,
}}
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
```
## API
Use a state and the `setApi` props to get an instance of the carousel API.
```tsx showLineNumbers {1,4,22}
import { type CarouselApi } from "@/components/ui/carousel";
export function Example() {
const [api, setApi] = React.useState<CarouselApi>();
const [current, setCurrent] = React.useState(0);
const [count, setCount] = React.useState(0);
React.useEffect(() => {
if (!api) {
return;
}
setCount(api.scrollSnapList().length);
setCurrent(api.selectedScrollSnap() + 1);
api.on("select", () => {
setCurrent(api.selectedScrollSnap() + 1);
});
}, [api]);
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
);
}
```
## Events
You can listen to events using the api instance from `setApi`.
```tsx showLineNumbers {1,4-14,16}
import { type CarouselApi } from "@/components/ui/carousel";
export function Example() {
const [api, setApi] = React.useState<CarouselApi>();
React.useEffect(() => {
if (!api) {
return;
}
api.on("select", () => {
// Do something on select.
});
}, [api]);
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
);
}
```
## Plugins
You can use the `plugins` prop to add plugins to the carousel.
```ts showLineNumbers {1,6-10}
import Autoplay from "embla-carousel-autoplay"
export function Example() {
return (
<Carousel
plugins={[
Autoplay({
delay: 2000,
}),
]}
>
// ...
</Carousel>
)
}
```

View File

@@ -0,0 +1,220 @@
---
title: Carousel
description: A carousel with motion and swipe built using Embla.
---
## Usage
```tsx
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel";
```
```tsx
<Carousel>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
```
## Examples
### Sizes
To set the size of the items, you can use the `basis` utility class on the `<CarouselItem />`.
```tsx title="Example" showLineNumbers {4-6}
// 33% of the carousel width.
<Carousel>
<CarouselContent>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
```
```tsx title="Responsive" showLineNumbers {4-6}
// 50% on small screens and 33% on larger screens.
<Carousel>
<CarouselContent>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
```
### Spacing
To set the spacing between the items, we use a `pl-[VALUE]` utility on the `<CarouselItem />` and a negative `-ml-[VALUE]` on the `<CarouselContent />`.
<Callout className="mt-6">
**Why:** I tried to use the `gap` property or a `grid` layout on the `
<CarouselContent />` but it required a lot of math and mental effort to get the
spacing right. I found `pl-[VALUE]` and `-ml-[VALUE]` utilities much easier to
use.
You can always adjust this in your own project if you need to.
</Callout>
<ComponentPreview
name="carousel-spacing"
title="Carousel"
description="A carousel with 3 items with a spacing of 1rem."
/>
```tsx title="Example" showLineNumbers /-ml-4/ /pl-4/
<Carousel>
<CarouselContent className="-ml-4">
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
```
```tsx title="Responsive" showLineNumbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/
<Carousel>
<CarouselContent className="-ml-2 md:-ml-4">
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
```
### Orientation
Use the `orientation` prop to set the orientation of the carousel.
```tsx showLineNumbers /vertical | horizontal/
<Carousel orientation="vertical | horizontal">
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
```
## Options
You can pass options to the carousel using the `opts` prop.
```tsx showLineNumbers {2-5}
<Carousel
opts={{
align: "start",
loop: true,
}}
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
```
## API
Use a state and the `setApi` props to get an instance of the carousel API.
```tsx showLineNumbers {1,4,22}
import { type CarouselApi } from "@/components/ui/carousel";
export function Example() {
const [api, setApi] = React.useState<CarouselApi>();
const [current, setCurrent] = React.useState(0);
const [count, setCount] = React.useState(0);
React.useEffect(() => {
if (!api) {
return;
}
setCount(api.scrollSnapList().length);
setCurrent(api.selectedScrollSnap() + 1);
api.on("select", () => {
setCurrent(api.selectedScrollSnap() + 1);
});
}, [api]);
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
);
}
```
## Events
You can listen to events using the api instance from `setApi`.
```tsx showLineNumbers {1,4-14,16}
import { type CarouselApi } from "@/components/ui/carousel";
export function Example() {
const [api, setApi] = React.useState<CarouselApi>();
React.useEffect(() => {
if (!api) {
return;
}
api.on("select", () => {
// Do something on select.
});
}, [api]);
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
);
}
```
## Plugins
You can use the `plugins` prop to add plugins to the carousel.
```ts showLineNumbers {1,6-10}
import Autoplay from "embla-carousel-autoplay"
export function Example() {
return (
<Carousel
plugins={[
Autoplay({
delay: 2000,
}),
]}
>
// ...
</Carousel>
)
}
```

View File

@@ -0,0 +1,90 @@
Name : Dialog
Description : A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
---
### import
```
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
```
---
### use
```dialog.mdx
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
```
---
### examples
```dialog-demo.tsx
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
export default function DialogDemo() {
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Edit Profile</Button>
</DialogTrigger>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Edit profile</DialogTitle>
<DialogDescription>
Make changes to your profile here. Click save when you're done.
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input id="name" value="Pedro Duarte" className="col-span-3" />
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Username
</Label>
<Input id="username" value="@peduarte" className="col-span-3" />
</div>
</div>
<DialogFooter>
<Button type="submit">Save changes</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)
}
```

View File

@@ -0,0 +1,85 @@
Name : Checkbox
Description : A control that allows the user to toggle between checked and not checked.
---
### import
```
import { Checkbox } from "@/components/ui/checkbox"
```
---
### use
```checkbox.mdx
<Checkbox />
```
---
### examples
```checkbox-demo.tsx
"use client"
import { Checkbox } from "@/components/ui/checkbox"
export default function CheckboxDemo() {
return (
<div className="flex items-center space-x-2">
<Checkbox id="terms" />
<label
htmlFor="terms"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions
</label>
</div>
)
}
```
```checkbox-disabled.tsx
import { Checkbox } from "@/components/ui/checkbox"
export default function CheckboxDisabled() {
return (
<div className="flex items-center space-x-2">
<Checkbox id="terms2" disabled />
<label
htmlFor="terms2"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions
</label>
</div>
)
}
```
```checkbox-with-text.tsx
"use client"
import { Checkbox } from "@/components/ui/checkbox"
export default function CheckboxWithText() {
return (
<div className="items-top flex space-x-2">
<Checkbox id="terms1" />
<div className="grid gap-1.5 leading-none">
<label
htmlFor="terms1"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
Accept terms and conditions
</label>
<p className="text-sm text-muted-foreground">
You agree to our Terms of Service and Privacy Policy.
</p>
</div>
</div>
)
}
```

View File

@@ -0,0 +1,347 @@
Name : Combobox
Description : Autocomplete input and command palette with a list of suggestions.
---
### import
```
"use client"
import * as React from "react"
import { Check, ChevronsUpDown } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from "@/components/ui/command"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
const frameworks = [
{
value: "next.js",
label: "Next.js",
},
{
value: "sveltekit",
label: "SvelteKit",
},
{
value: "nuxt.js",
label: "Nuxt.js",
},
{
value: "remix",
label: "Remix",
},
{
value: "astro",
label: "Astro",
},
]
export function ComboboxDemo() {
const [open, setOpen] = React.useState(false)
const [value, setValue] = React.useState("")
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-[200px] justify-between"
>
{value
? frameworks.find((framework) => framework.value === value)?.label
: "Select framework..."}
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command>
<CommandInput placeholder="Search framework..." />
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
{frameworks.map((framework) => (
<CommandItem
key={framework.value}
onSelect={(currentValue) => {
setValue(currentValue === value ? "" : currentValue)
setOpen(false)
}}
>
<Check
className={cn(
"mr-2 h-4 w-4",
value === framework.value ? "opacity-100" : "opacity-0"
)}
/>
{framework.label}
</CommandItem>
))}
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
)
}
```
---
### use
---
### examples
```combobox-dropdown-menu.tsx
"use client"
import * as React from "react"
import { Calendar, MoreHorizontal, Tags, Trash, User } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
const labels = [
"feature",
"bug",
"enhancement",
"documentation",
"design",
"question",
"maintenance",
]
export default function ComboboxDropdownMenu() {
const [label, setLabel] = React.useState("feature")
const [open, setOpen] = React.useState(false)
return (
<div className="flex w-full flex-col items-start justify-between rounded-md border px-4 py-3 sm:flex-row sm:items-center">
<p className="text-sm font-medium leading-none">
<span className="mr-2 rounded-lg bg-primary px-2 py-1 text-xs text-primary-foreground">
{label}
</span>
<span className="text-muted-foreground">Create a new project</span>
</p>
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm">
<MoreHorizontal />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[200px]">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuGroup>
<DropdownMenuItem>
<User className="mr-2 h-4 w-4" />
Assign to...
</DropdownMenuItem>
<DropdownMenuItem>
<Calendar className="mr-2 h-4 w-4" />
Set due date...
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Tags className="mr-2 h-4 w-4" />
Apply label
</DropdownMenuSubTrigger>
<DropdownMenuSubContent className="p-0">
<Command>
<CommandInput
placeholder="Filter label..."
autoFocus={true}
/>
<CommandList>
<CommandEmpty>No label found.</CommandEmpty>
<CommandGroup>
{labels.map((label) => (
<CommandItem
key={label}
onSelect={(value) => {
setLabel(value)
setOpen(false)
}}
>
{label}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem className="text-red-600">
<Trash className="mr-2 h-4 w-4" />
Delete
<DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
)
}
```
```combobox-popover.tsx
"use client"
import * as React from "react"
import {
ArrowUpCircle,
CheckCircle2,
Circle,
HelpCircle,
LucideIcon,
XCircle,
} from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
type Status = {
value: string
label: string
icon: LucideIcon
}
const statuses: Status[] = [
{
value: "backlog",
label: "Backlog",
icon: HelpCircle,
},
{
value: "todo",
label: "Todo",
icon: Circle,
},
{
value: "in progress",
label: "In Progress",
icon: ArrowUpCircle,
},
{
value: "done",
label: "Done",
icon: CheckCircle2,
},
{
value: "canceled",
label: "Canceled",
icon: XCircle,
},
]
export default function ComboboxPopover() {
const [open, setOpen] = React.useState(false)
const [selectedStatus, setSelectedStatus] = React.useState<Status | null>(
null
)
return (
<div className="flex items-center space-x-4">
<p className="text-sm text-muted-foreground">Status</p>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
size="sm"
className="w-[150px] justify-start"
>
{selectedStatus ? (
<>
<selectedStatus.icon className="mr-2 h-4 w-4 shrink-0" />
{selectedStatus.label}
</>
) : (
<>+ Set status</>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="p-0" side="right" align="start">
<Command>
<CommandInput placeholder="Change status..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup>
{statuses.map((status) => (
<CommandItem
key={status.value}
onSelect={(value) => {
setSelectedStatus(
statuses.find((priority) => priority.value === value) ||
null
)
setOpen(false)
}}
>
<status.icon
className={cn(
"mr-2 h-4 w-4",
status.value === selectedStatus?.value
? "opacity-100"
: "opacity-40"
)}
/>
<span>{status.label}</span>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
</div>
)
}
```

View File

@@ -0,0 +1,239 @@
Name : Date Picker
Description : A date picker component with range and presets.
---
### import
```
"use client"
import * as React from "react"
import { format } from "date-fns"
import { Calendar as CalendarIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
export function DatePickerDemo() {
const [date, setDate] = React.useState<Date>()
return (
<Popover>
<PopoverTrigger asChild>
<Button
variant={"outline"}
className={cn(
"w-[280px] justify-start text-left font-normal",
!date && "text-muted-foreground"
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
{date ? format(date, "PPP") : <span>Pick a date</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={date}
onSelect={setDate}
initialFocus
/>
</PopoverContent>
</Popover>
)
}
```
---
### use
---
### examples
```date-picker-demo.tsx
"use client"
import * as React from "react"
import { format } from "date-fns"
import { Calendar as CalendarIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
export default function DatePickerDemo() {
const [date, setDate] = React.useState<Date>()
return (
<Popover>
<PopoverTrigger asChild>
<Button
variant={"outline"}
className={cn(
"w-[280px] justify-start text-left font-normal",
!date && "text-muted-foreground"
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
{date ? format(date, "PPP") : <span>Pick a date</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={date}
onSelect={setDate}
initialFocus
/>
</PopoverContent>
</Popover>
)
}
```
```date-picker-with-presets.tsx
"use client"
import * as React from "react"
import { addDays, format } from "date-fns"
import { Calendar as CalendarIcon } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
export default function DatePickerWithPresets() {
const [date, setDate] = React.useState<Date>()
return (
<Popover>
<PopoverTrigger asChild>
<Button
variant={"outline"}
className={cn(
"w-[280px] justify-start text-left font-normal",
!date && "text-muted-foreground"
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
{date ? format(date, "PPP") : <span>Pick a date</span>}
</Button>
</PopoverTrigger>
<PopoverContent className="flex w-auto flex-col space-y-2 p-2">
<Select
onValueChange={(value) =>
setDate(addDays(new Date(), parseInt(value)))
}
>
<SelectTrigger>
<SelectValue placeholder="Select" />
</SelectTrigger>
<SelectContent position="popper">
<SelectItem value="0">Today</SelectItem>
<SelectItem value="1">Tomorrow</SelectItem>
<SelectItem value="3">In 3 days</SelectItem>
<SelectItem value="7">In a week</SelectItem>
</SelectContent>
</Select>
<div className="rounded-md border">
<Calendar mode="single" selected={date} onSelect={setDate} />
</div>
</PopoverContent>
</Popover>
)
}
```
```date-picker-with-range.tsx
"use client"
import * as React from "react"
import { addDays, format } from "date-fns"
import { Calendar as CalendarIcon } from "lucide-react"
import { DateRange } from "react-day-picker"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
export default function DatePickerWithRange({
className,
}: React.HTMLAttributes<HTMLDivElement>) {
const [date, setDate] = React.useState<DateRange | undefined>({
from: new Date(2022, 0, 20),
to: addDays(new Date(2022, 0, 20), 20),
})
return (
<div className={cn("grid gap-2", className)}>
<Popover>
<PopoverTrigger asChild>
<Button
id="date"
variant={"outline"}
className={cn(
"w-[300px] justify-start text-left font-normal",
!date && "text-muted-foreground"
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
{date?.from ? (
date.to ? (
<>
{format(date.from, "LLL dd, y")} -{" "}
{format(date.to, "LLL dd, y")}
</>
) : (
format(date.from, "LLL dd, y")
)
) : (
<span>Pick a date</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
initialFocus
mode="range"
defaultMonth={date?.from}
selected={date}
onSelect={setDate}
numberOfMonths={2}
/>
</PopoverContent>
</Popover>
</div>
)
}
```

Some files were not shown because too many files have changed in this diff Show More