Lovable، Bolt، اور v0 جیسے ٹولز پہلی بار استعمال کرتے وقت جادو کی طرح محسوس ہوتے ہیں۔ سچ میں، میں نے پہلی بار ایسا کچھ دیکھا تو میں حیران رہ گیا تھا… اور آپ یہ سب چیٹ میں کر سکتے ہیں! یہ صرف جنگلی تھا۔ مجھے یہ پورا وجودی بحران اس وقت پڑا جب میں نے پہلی بار لو ایبل کو آزمایا۔
لیکن کیا آپ نے کبھی سوچا ہے کہ واقعی نیچے کیا ہو رہا ہے؟ مثال کے طور پر، ایک ایپ کے لیے یہ کیسے ممکن ہے کہ وہ مکمل طور پر مختلف ایپس کو ترتیب دے جن کا تجربہ، اشتراک، ڈاؤن لوڈ، وغیرہ کیا جا سکتا ہے؟
کہیں، ایک AI ماڈل کوڈ لکھ رہا ہے۔ یہ واضح ہے۔ لیکن کیسے؟ آپ کو اس کوڈ کو انسٹال، بنانے اور چلانے کی ضرورت ہے۔ اور جس چیز کے بارے میں مجھے تھوڑا سا شبہ تھا وہ یہ ہے کہ ان دنوں ایسا نہیں لگتا کہ کوڈ کو پھانسی دینے سے پہلے پڑھا گیا ہے۔ یہ خراب ہو سکتا ہے، سست ہو سکتا ہے، یا یہاں تک کہ وہ کام کرنے کی کوشش کر سکتا ہے جو اسے نہیں کرنا چاہیے، آپ کے پورے سسٹم کا صفایا کر سکتا ہے۔ rm -rf. چونکہ یہ AI کی وجہ سے ہوا، ہم 100% یقین سے نہیں کہہ سکتے۔
یہ وہ مسئلہ ہے جس پر اس مضمون میں توجہ دی گئی ہے۔
یہاں ہم آپ کا اپنا دلکش انداز AI ایپ بلڈر بنائیں گے۔ یہ کلون نہیں ہوگا۔ بلکہ، آئیے لو ایبل کی منطق پر گہری نظر ڈالیں اور دیکھیں کہ یہ عملی طور پر کیسے کام کرتی ہے۔ میں UI کو بہت بنیادی رکھوں گا۔
ہمارے پروجیکٹ کے لیے، صارفین ایپ کو سادہ انگریزی میں بیان کر سکتے ہیں اور AI ایجنٹ الگ تھلگ کلاؤڈ سینڈ باکس میں کوڈ لکھے گا۔ AI اپنی غلطیوں کو درست کرتا ہے اور پھر ریئل ٹائم پیش نظارہ دکھاتا ہے۔ یہاں سے، صارفین چیٹ کے ذریعے تعمیر جاری رکھ سکتے ہیں، کسی بھی ورژن پر واپس جا سکتے ہیں، اور ایک کلک کے ساتھ تیار شدہ ایپ کو شائع کر سکتے ہیں۔
ہم یہاں کیا احاطہ کرتے ہیں:
اس ٹیوٹوریل میں آپ سب کچھ شروع سے بنائیں گے۔ اس کورس میں آپ جو کچھ سیکھیں گے وہ یہ ہے:
-
AI سے تیار کردہ کوڈ کو سینڈ باکس کی ضرورت کیوں ہے۔
-
30 سیکنڈ یا اس سے زیادہ کی بجائے تقریباً 4 سیکنڈ میں نیا سینڈ باکس تیار کرنے کے لیے میموری اسنیپ شاٹس کا استعمال کیسے کریں
-
ایک ایجنٹ لوپ کیسے بنایا جائے جو کوڈ لکھتا ہے، اپنے اعمال کی تصدیق کرتا ہے، اور اپنی غلطیوں کو درست کرتا ہے۔
-
ایجنٹ براؤزر کے ساتھ اصل وقت میں کیا کر رہا ہے اسے کیسے اسٹریم کیا جائے (تاکہ صفحہ کے تازہ ہونے پر یہ ضائع نہ ہو)
-
اپنے گیٹ وے کے ذریعے ہاٹ ری لوڈ کے ساتھ لائیو پیش نظارہ کیسے ڈسپلے کریں۔
-
سینڈ باکس میں ٹوکن ڈالے بغیر Git کے ساتھ تمام تبدیلیوں کا ورژن کیسے بنائیں
-
بیکار سینڈ باکس کو سونے کے لیے کیسے رکھیں، ضرورت پڑنے پر اسے جگائیں، اور حتمی ایپ شائع کریں۔
یہ کچھ جدید تصورات کا احاطہ کرتا ہے، لیکن اگر آپ اس پر عمل کرتے ہیں، تو آپ راستے میں بہت کچھ سیکھیں گے۔ اسے بناتے وقت یقیناً ایسا ہی تھا۔
انڈیکس
منصوبے کیا ہیں (فن تعمیر)
کوڈ کو دیکھنے سے پہلے، یہ سمجھنا مددگار ہے کہ سب کچھ ایک ساتھ کیسے فٹ بیٹھتا ہے۔ کیونکہ پہلے سمجھنے کے قابل بہت سارے تصورات ہیں۔
ایپ کو تین عملوں اور دو بنیادی ڈھانچے میں تقسیم کیا گیا ہے۔ ایک چیز جس کے بارے میں میں شروع سے ہی سخت تھا وہ یہ تھا کہ ویب ایپس کو خود AI ایجنٹوں کو نہیں چلنا چاہئے، اور ایجنٹوں کو سینڈ باکس کے اندر نہیں چلنا چاہئے۔ آپ تھوڑی دیر بعد دیکھیں گے کہ یہ کیوں ضروری ہے۔
شروع سے اختتام تک بہاؤ مندرجہ ذیل ہے:
پرامپٹ بھیجیں۔
جب صارف پرامپٹ داخل کرتا ہے، تو ویب ایپ (Next.js) اسے محفوظ کرتی ہے، Postgres میں ایک "Execut” بناتی ہے، کام کو قطار میں لگاتی ہے، اور فوراً واپس آجاتی ہے۔ لہذا صارف کو کچھ HTTP درخواست کا انتظار کرنے کی ضرورت نہیں ہے جب کہ ایجنٹ اپنا کام کرتا ہے۔
ایجنٹ پر عمل درآمد
ایک کارکن کا عمل کام کو اٹھاتا ہے۔ پہلے ہم چیک کرتے ہیں کہ آیا پروجیکٹ میں سینڈ باکس چل رہا ہے اور پھر ایجنٹ لوپ شروع کریں۔ LLM فیصلہ کرتا ہے کہ کیا کرنا ہے، اور تمام ٹول کالز جو اسے کرتی ہیں (فائل بنانا، کمانڈز چلانا، پیکجز انسٹال کرنا وغیرہ) دراصل سینڈ باکس کے اندر ہی ہوتی ہیں۔
ہر ایک قدم کو ڈیٹا بیس میں ایک ایونٹ کے طور پر محفوظ کیا جاتا ہے، اور اس طرح براؤزر اسے حقیقی وقت میں بازیافت کرتا ہے۔
پیش نظارہ دکھائیں۔
تیار کردہ ایپ سینڈ باکس کے اندر اپنے وائٹ ڈویلپمنٹ سرور پر چلتی ہے۔ ہمارے پاس ایک چھوٹی گیٹ وے سروس ہے جو پراکسینگ کرتی ہے۔ http:// اس ڈویلپمنٹ سرور پر، بشمول WebSocket جو Vite گرم دوبارہ لوڈ کے لیے استعمال کرتا ہے۔
لہذا جب کوئی ایجنٹ کسی فائل میں ترمیم کرتا ہے تو، پیش نظارہ خود بخود اپ ڈیٹ ہوجاتا ہے، لہذا جب بھی میں اسے دیکھتا ہوں ایمانداری سے یہ اب بھی بہت اچھا محسوس ہوتا ہے۔
محفوظ کریں اور شائع کریں۔
ایجنٹ کے مکمل ہونے کے بعد، کارکن نئے ورژن میں تبدیلیوں کا ارتکاب کرتا ہے۔ اور جب صارف پبلش پر کلک کرتا ہے تو ایپ بن جاتی ہے اور سٹیٹک فائلز S3 پر اپ لوڈ ہو جاتی ہیں، اس لیے شائع شدہ سائٹ اس وقت بھی کام کرتی رہتی ہے جب سینڈ باکس سلیپ موڈ میں ہو۔
یہ ہماری درخواست کا اعلیٰ سطحی فن تعمیر ہے۔ سیدھے الفاظ میں:
-
Next.js: UI اور API پرت
-
کارکن(Node.js +
pg-boss): ایجنٹ کی پرت -
گیٹ وے (Node.js پراکسی): پیش نظارہ پرت
-
پوسٹگریس: حیثیت اور کام کی قطار کی پرتیں۔
-
کلاؤڈ سینڈ باکس: پھانسی کی پرت
-
S3 (مقامی MinIO): اسٹوریج پرت
-
مطلوبہ ایل ایل ایم (اس معاملے میں کلاڈ یا جی پی ٹی): تخمینہ پرت
آپ کو سینڈ باکس کی ضرورت کیوں ہے؟
اگر آپ اس کے بارے میں سوچتے ہیں تو، پوری مصنوعات بنیادی طور پر "چلانے والا کوڈ ہے جس کا کسی نے جائزہ نہیں لیا ہے۔” ایک مشیر لکھتا ہے، npm install ایک بار جب انسٹالیشن اسکرپٹ ان پیکجز کو درآمد کر لیتا ہے جو تقریباً کچھ بھی چلا سکتے ہیں، ڈویلپمنٹ سرور ان سب کو چلانا شروع کر دیتا ہے۔ ایسا کوئی طریقہ نہیں ہے کہ میں اسے اپنے سرور پر چلاوں اور نہ ہی آپ کو۔
لہذا ہر پروجیکٹ کا اپنا الگ تھلگ سینڈ باکس ہوتا ہے، جو بنیادی طور پر کلاؤڈ میں ایک چھوٹا VM ہوتا ہے۔ اس کو حاصل کرنے کے لیے، سینڈ باکس فراہم کنندہ کا انتخاب کرتے وقت آپ کو واقعی ضرورت ہے:
-
معطل اور دوبارہ شروع کریں: زیادہ تر منصوبے زیادہ تر وقت بیکار رہتے ہیں۔ میں ان کو سونا چاہتا تھا اور سیکنڈوں میں ان کی یادوں کو برقرار رکھتے ہوئے انہیں دوبارہ جگانا چاہتا تھا۔
-
فائلیں، کمانڈز، اور ٹرمینل: ایجنٹ کو فائلوں کو پڑھنے اور لکھنے اور کمانڈ پر عمل کرنے کی ضرورت ہوتی ہے، اور صارف کو اصلی شیل فراہم کرنا اچھا خیال ہو سکتا ہے۔
پروڈکشن میں اس طرح کی کوئی چیز استعمال کرنے پر غور کرتے وقت جانچنے کے لیے اور بھی بہت سی چیزیں ہیں، لیکن میرے لیے صرف یہی چیلنجنگ تقاضے تھے۔
اس کے لیے ہم Tensorlake sandbox استعمال کر رہے ہیں۔ واضح طور پر، اس مخصوص کو استعمال کرنے کی کوئی خاص وجہ نہیں ہے۔ E2B، ڈیٹونا، موڈل یا یہاں تک کہ ہمارا اپنا فائر کریکر سیٹ اپ سب کام کرے گا اور آپ اپنی پسند کا انتخاب کرنے کے لیے آزاد ہیں۔ میں نے اسے پہلے ہی کچھ پروجیکٹس پر استعمال کیا ہے اور سینڈ باکسز کے لیے یہ بالکل کام کرتا ہے۔ یہ خاص طور پر ہمارے جیسے استعمال کے معاملات کے لیے درست ہے۔
میمو: تمام سینڈ باکس کوڈ ایک ہی پیکج میں محفوظ ہے (packages/sandbox)۔ لہذا اگر آپ فراہم کنندگان کو تبدیل کرنا چاہتے ہیں، تو یہ واحد جگہ ہے جہاں سے آپ کو رابطہ کرنا چاہیے۔ باقی ایپ کو یہ بھی نہیں معلوم کہ وہ کس فراہم کنندہ سے بات کر رہی ہے۔
پروجیکٹ کیسے ترتیب دیا جائے۔
شروع کرنے سے پہلے، یقینی بنائیں کہ آپ کے پاس درج ذیل انسٹال ہیں:
آپ کو اپنے سینڈ باکس فراہم کنندہ اور LLM (یا تو انتھروپک یا اوپن اے آئی، جو بھی آپ چاہیں) کے لیے ایک API کلید کی بھی ضرورت ہوگی۔
ریپوزٹری کو کلون کرکے اور انحصار کو انسٹال کرکے شروع کریں۔
git clone https://github.com/shricodev/lovable-build-tensorlake-aws.git
cd lovable-build-tensorlake-aws
pnpm install
اگلا، ایک ماحول فائل بنائیں اور کلید درج کریں۔
cp .env.example .env
# Add your sandbox and LLM keys, and generate AUTH_SECRET with:
openssl rand -base64 32
اب آئیے مقامی انفراسٹرکچر شروع کریں، ڈیٹا بیس ٹیبل بنائیں، اور سٹوریج کی بالٹیاں ترتیب دیں۔
# Start Postgres and MinIO
pnpm infra:up
# Create the database tables
pnpm db:migrate
# Create the bucket and lock it down
pnpm s3:setup
اس کے بعد ہم ایک بنیادی سنیپ شاٹ بناتے ہیں جہاں سے تمام نئے منصوبے شروع ہوتے ہیں (اس پر مزید بعد میں)۔ اس میں تقریباً 45 سیکنڈ لگیں گے:
pnpm sandbox:build-base
آخر میں، سب کچھ شروع کریں.
# web on :3000, preview gateway on :4000
pnpm dev
کھلا http://localhost:3000لاگ ان کریں اور اپنی ایپ کی وضاحت کریں۔ بس!
میمو: ایپ GitHub لاگ ان کو سپورٹ کرتی ہے، لیکن ایک سادہ ڈویلپر لاگ ان بھی فراہم کرتی ہے، لہذا آپ اپنی GitHub OAuth ایپ بنانے سے پہلے اسے آزما سکتے ہیں۔ فکر نہ کرو۔ ڈویلپمنٹ لاگ ان ہمیشہ پیداواری ماحول میں غیر فعال ہوتے ہیں۔
درخواست کے بنیادی اجزاء
یہ منصوبہ بہت بڑا ہے۔ اسے لائن بہ لائن پڑھنے میں ایک گھنٹہ لگے گا، لہذا میں ان بنیادی اجزاء پر توجہ دوں گا جو نظام کو اصل میں کام کرتے ہیں۔ میں ڈیش بورڈ، لاگ ان، کوڈ ایڈیٹر وغیرہ کو چھوڑ دوں گا کیونکہ یہ بہت عام خصوصیات ہیں۔
میمو: اس کا مطلب ہے کہ ذیل میں کوڈ کا ٹکڑا اس کے اہم حصوں میں چھوٹا کر دیا گیا ہے۔ آپ کو ذخیرہ میں مکمل کوڈ مل سکتا ہے۔
سینڈ باکس کے ساتھ جلدی شروع کریں۔
تمام تخلیق کردہ ایپس ایک ہی ٹیمپلیٹ سے شروع ہوتی ہیں: Vite، React، TypeScript، Tailwind، اور چند عام لائبریریاں۔ ایسا کرنے کا سادہ طریقہ ہر نئے پروجیکٹ کے لیے ہے:
-
ایک نیا سینڈ باکس بنائیں
-
سانچہ اپ لوڈ کریں۔
-
چلائیں
npm install -
ڈویلپمنٹ سرور شروع کریں۔
اس نے کام کیا، لیکن اس میں کچھ وقت لگا۔ 33.4 سیکنڈ میرے ٹیسٹوں میں، اس سے پہلے کہ یہ پیش نظارہ تک پہنچ جائے۔ ان میں سے زیادہ تر (تقریباً 23 سیکنڈ) npm install ایک وی سی پی یو پر چلتا ہے۔ میں آپ کے بارے میں نہیں جانتا، لیکن جب بھی میں کوئی نیا پروجیکٹ شروع کرتا ہوں، میں خود کو زیادہ دیر تک اسپنر کو گھورتا ہوا نہیں پاتا۔
حل یہ ہے کہ یہ سب کچھ کیا جائے۔ ایک بارنتائج کو میموری اسنیپ شاٹ کے طور پر محفوظ کریں۔ میموری سنیپ شاٹس فائلوں، RAM، اور چلانے کے عمل کو پکڑتے ہیں۔ لہذا جب آپ بحال کرتے ہیں، آپ کا ترقیاتی سرور پہلے سے ہی چل رہا ہے۔ ریبوٹ کی ضرورت نہیں ہے۔
بنیادی سنیپ شاٹ بلڈر کا جوہر حسب ذیل ہے:
export async function buildBaseSnapshot(log: Logger) {
// Cold path, done once: create, upload template, npm install, git init,
// verify it builds, start the dev server and warm up Vite's cache.
const { ps } = await coldCreateFromTemplate({
name: `base-${Date.now()}`,
log,
verify: true,
});
try {
// Memory checkpoint: files + RAM + running processes.
const snapshotId = await ps.checkpoint();
writeBaseSnapshot({ snapshotId, createdAt: new Date().toISOString() });
} finally {
await ps.terminate();
}
}
پھر کسی نئے پروجیکٹ کے لیے سینڈ باکس بنانا صرف اسے بحال کرتا ہے اور اسے لاک کر دیتا ہے۔
static async createFromSnapshot(opts: { snapshotId: string; name: string; log: Logger }) {
const sb = await Sandbox.create({ snapshotId: opts.snapshotId, name: opts.name, timeoutSecs: 600 });
const ps = new ProjectSandbox(sb, opts.log);
await sb.update({
exposedPorts: [5173], // the Vite dev server, reachable through the proxy
allowUnauthenticatedAccess: false, // the port URL is never public
network: {
allowInternetAccess: true,
allowOut: ["registry.npmjs.org"], // npm and nothing else
denyOut: [],
},
});
return ps;
}
یہاں چند باتیں قابل توجہ ہیں:
-
exposedPortsآپ اپنے فراہم کنندہ کی پراکسی کے ذریعے اپنے ڈویلپمنٹ سرور سے جڑ سکتے ہیں، لیکن صرف اس صورت میں جب آپ کے پاس API کلید ہو۔ ہم اسے بعد میں گیٹ وے میں استعمال کریں گے۔ -
کہ
networkبلاک ایک وائٹ لسٹ ہے۔ ایک بارallowOutاگر کوئی آئٹم موجود ہے تو دیگر تمام آئٹمز کو مسدود کر دیا جائے گا۔میں نے اصل میں اس کا تجربہ کیا۔
example.com،github.comکلاؤڈ میٹا ڈیٹا آئی پی وغیرہ سبھی کو بلاک کردیا گیا تھا لیکن این پی ایم نے پھر بھی ٹھیک کام کیا۔ -
سینڈ باکس کے ماحول میں کوئی راز نہیں ہیں۔ کوئی LLM کلید نہیں، کوئی ڈیٹا بیس URL نہیں، کوئی AWS کلید نہیں، کچھ نہیں۔ لہذا یہاں تک کہ اگر ایک تیار کردہ ایپ یا فوری انجیکشن کچھ چوری کرنے کی کوشش کرتا ہے، وہاں چوری کرنے کے لیے کچھ نہیں ہے۔
پیش نظارہ کے اصل میں لوڈ ہونے تک کی پیمائشیں یہ ہیں:
| سڑک | گھنٹہ |
|---|---|
| کولڈ (بنائیں، انسٹال کریں، ڈویلپمنٹ سرور شروع کریں) | 33.4 سیکنڈ |
| میموری اسنیپ شاٹ سے بحال کریں۔ | 4.0 سیکنڈ |
| سوئے ہوئے سینڈ باکس کو جگائیں۔ | 2.4 سیکنڈ |
یہ تقریباً 8 گنا تیز ہے۔ یہ کتنا ٹھنڈا ہے؟
ایجنٹ لوپ
ایجنٹ لوپ پورے نظام کا دماغ ہے۔ یہ ہر بار چلتا ہے جب صارف کوئی پرامپٹ بھیجتا ہے۔
خیال، چاہے عمل درآمد نہ ہو، سادہ ہے۔ اپنے LLM کو ایک مقصد اور کچھ ٹولز دیں، اسے کال کریں، نتائج کو فیڈ بیک کریں، اور مکمل ہونے تک اعادہ کریں۔
مشیروں کو ملنے والے ٹولز یہ ہیں:
-
list_files،read_file،write_file،edit_fileاورdelete_file -
run_commandاس طرح فوری چیک کے لیے:npx tsc --noEmit -
install_packagesاین پی ایم پیکیج شامل کریں۔ -
get_dev_server_logsاورget_browser_errorsڈیبگنگ کے لیے -
finishایجنٹ اسے کال کرتا ہے جب اسے لگتا ہے کہ یہ ہو گیا ہے۔
ہر ٹول زوڈ اسکیما کے ساتھ آتا ہے۔ run فنکشن یہاں edit_file مثال کے طور پر:
export const editFile = defineTool({
name: "edit_file",
description:
"Replace one exact snippet in a file. `search` must match exactly and occur exactly once.",
schema: z.object({
path: z.string(),
search: z.string().min(1),
replace: z.string(),
}),
async run({ path, search, replace }, { sandbox }) {
const text = await sandbox.readFile(path);
const count = text.split(search).length - 1;
if (count !== 1) {
return {
isError: true,
content: `search text occurs ${count} times in ${path}`,
};
}
await sandbox.writeFile(
path,
text.replace(search, () => replace),
);
return { content: `Edited ${path}`, changedFiles: [path] };
},
});
Zod اسکیما یہاں دو کام کرتا ہے: LLM کے لیے JSON اسکیما میں تبدیل ( z.toJSONSchema) یہ سینڈ باکس سے ٹکرانے سے پہلے ماڈل کی بھیجی ہوئی ہر چیز کی توثیق بھی کرتا ہے۔ اگر ان پٹ غلط ہے تو، پورے عمل کو ختم کرنے کے بجائے ماڈل میں ایک خرابی واپس آ جاتی ہے۔
پھر اصل لوپ چلتا ہے.
while (true) {
if (signal.aborted) return result("cancelled");
const res = await llm.chat({
system: SYSTEM_PROMPT,
messages,
tools,
signal,
onText,
});
messages.push(res.message);
const results = [];
for (const call of res.message.toolCalls) {
const out = await executeTool(call.name, call.input, ctx); // validate + run
results.push({
type: "tool_result",
toolCallId: call.id,
content: out.content,
isError: out.isError,
});
if (out.finish) finishCalled = true;
}
if (!finishCalled) {
messages.push({ role: "user", content: results });
continue;
}
// The agent says it's done. Now we check. (next section)
}
کہ llm.chat کال ایک چھوٹا ریپر ہے جو ایک ہی انٹرفیس کے ساتھ اینتھروپک اور اوپن اے آئی دونوں کو سپورٹ کرتا ہے، جس سے آپ UI میں ڈراپ ڈاؤن سے ماڈلز کو تبدیل کر سکتے ہیں۔
انتھروپک سائیڈ پر، تیزی سے کیشنگ کو فعال کیا گیا ہے، اور واضح طور پر، یہ لاگت کے نقطہ نظر سے زیادہ تر بوجھ کو بچاتا ہے۔ ایک عام موڑ 120,000 سے زیادہ ٹوکن پڑھتا ہے، جن میں سے تقریباً سبھی سیدھے کیشے سے آتے ہیں۔
فائل کے راستوں کو محفوظ رکھنا
اب یہ تھوڑا سا ڈرپوک ہے، لیکن مجھے یہ اس لیے ملا کیونکہ میں نے ارد گرد کچھ کھدائی کی تھی۔ سینڈ باکس فائل API درج ذیل راستوں کو روکتا ہے۔ .. لیکن خوشی سے علامتی لنکس پر عمل کریں۔. تو پیدا کردہ کوڈ ہے۔ leak.txt اس سے مراد ہے۔ /etc/passwdپڑھنا leak.txt ہم آپ کی پاس ورڈ فائل واپس کر دیں گے۔ بہت اچھا نہیں ہے۔
لہذا تمام فائل ٹولز کسی بھی چیز کو چھونے سے پہلے سینڈ باکس کے اندر اصل راستہ چیک کرتے ہیں۔
async safePath(relPath: string) {
const abs = resolveProjectPath(relPath); // rejects "..", absolute paths, NUL bytes
const r = await this.sb.run("realpath", { args: ["-m", "--", abs] });
const real = r.stdout.trim();
if (!isInsideApp(real)) throw new SandboxPathError(relPath, "resolves outside the project");
return real;
}
realpath -m یہ تمام علامتی روابط کی پیروی کرتا ہے اور آپ کو بتاتا ہے کہ راستہ دراصل کہاں اشارہ کرتا ہے۔ کال ناکام ہو جائے گی اگر پراجیکٹ فولڈر کے باہر ختم کر دیا جائے گا۔
سیاق و سباق کو چھوٹا رکھیں
ہر نئے پرامپٹ پر تمام پچھلی ٹول کالز کو دوبارہ چلانے کے بجائے، ہر موڑ ایک نیا ڈائیلاگ شروع کرتا ہے:
-
ہر پچھلے موڑ کا ایک سطری خلاصہ (صارف نے کیا درخواست کی اور ایجنٹ نے کیا کیا)
-
فائل ٹری اور انسٹال شدہ پیکجوں کی فہرست
-
آج
src/App.tsx
ایجنٹ اس آلے کو ہر چیز کو پڑھنے کے لیے استعمال کرتا ہے جس کی اسے ضرورت ہے۔ پروجیکٹ میں 20 پرامپٹس ہونے کے بعد بھی یہ گردش کی لاگت کو تقریباً فلیٹ رکھتا ہے۔
ایجنٹوں کو ان کے اپنے اعمال کی تصدیق کرنے دیں۔
LLM واقعی اعتماد سے متاثر کن ہے۔ وہ آپ کو یہ بتاتے ہوئے خوش ہوں گے کہ ایک بار جب تعمیر ڈیفالٹ کے طور پر شروع ہو جاتی ہے، سب کچھ کام کرتا ہے۔ تو جب ایجنٹ بلاتا ہے۔ finishہم صرف اس کے لئے ان کے الفاظ نہیں لیتے ہیں۔ سینڈ باکس کے اندر، ہم تین چیک چلاتے ہیں:
export async function runChecks(sandbox: ProjectSandbox) {
const tsc = await sandbox.exec("npx tsc --noEmit -p . 2>&1", {
timeoutSecs: 120,
});
const build = await sandbox.exec(
"npx vite build --outDir /tmp/build --emptyOutDir --logLevel error 2>&1",
{ timeoutSecs: 180 },
);
const render = await renderCheck(sandbox); // renders the app once in a fake DOM
return {
ok: tsc.exitCode === 0 && build.exitCode === 0 && render.ok,
typecheck: { ok: tsc.exitCode === 0, output: tsc.stdout },
build: { ok: build.exitCode === 0, output: build.stdout },
render,
};
}
پہلے دو کافی واضح ہیں۔ تیسرا وہ جگہ ہے جہاں یہ دلچسپ ہو جاتا ہے۔ بہت سے کیڑے صرف رن ٹائم پر ظاہر ہوتے ہیں۔ Cannot read properties of undefined (reading 'map'). اس کا معمول کا جواب ہیڈ لیس براؤزر ہے، لیکن میں واقعتا اس راستے پر نہیں جانا چاہتا تھا کیونکہ یہ ایک چھوٹے سینڈ باکس میں بھاری اور سست ہوگا۔
لہذا ٹیمپلیٹ ایک چھوٹا اسکرپٹ فراہم کرتا ہے جو ایپ کو ایک بار پیش کرتا ہے، اس طرح: happy-dom (Node.js میں جعلی DOM) اور وائٹ ssrLoadModule:
GlobalRegistrator.register({ url: "http://localhost:5173/" });
document.body.innerHTML = '';
console.error = (...args) => errors.push(args.join(" "));
await server.ssrLoadModule("/src/main.tsx"); // runs the real app entry
await new Promise((r) => setTimeout(r, 1500)); // let React render
const rendered = document.getElementById("root").innerHTML.trim().length > 0;
console.log(
JSON.stringify({ ok: rendered && errors.length === 0, rendered, errors }),
);
یہ تقریباً 2 سیکنڈ لیتا ہے اور اسے پکڑتا ہے۔ undefined.map صحیح لائن کے ساتھ تصادم App.tsx. ٹھیک ہے
اگر کوئی بھی چیک ناکام ہو جاتا ہے، تو یہ غلطی براہ راست ایجنٹ کو ایک نئے پیغام کے طور پر بھیج دی جاتی ہے، اور ایجنٹ اسے ٹھیک کرنے کے لیے دوسرا چکر لگاتا ہے۔
lastCheck = await runChecks(sandbox);
if (lastCheck.ok) return result("succeeded");
if (healRounds >= maxHeal)
return result("failed", { error: describeFailures(lastCheck) });
healRounds++;
messages.push({
role: "user",
content: [
...results,
{
type: "text",
text: `Verification failed. Fix these problems, then call finish again.nn${describeFailures(lastCheck)}`,
},
],
});
پہلے سے طے شدہ طور پر یہ 3 راؤنڈ کے بعد رک جاتا ہے۔ اگر اس کے بعد بھی یہ ٹوٹ جاتا ہے، تو صارف کو اصل غلطی کے ساتھ ایک دو ٹوک "یہ آپریشن مکمل نہیں کیا جا سکتا” کا پیغام ملے گا۔
اپنی پیشرفت کو اپنے براؤزر میں سٹریم کریں۔
ایجنٹ کارکن پر چلتا ہے، لیکن صارف براؤزر کی طرف دیکھ رہا ہے۔ تو کسی نہ کسی طرح میں نے ہر قدم لکھا (” src/App.tsx"،” npx tsc --noEmit"،” پاس شدہ معائنہ” وغیرہ)، آپ کو ایک جگہ سے دوسری جگہ جانا پڑتا ہے۔
کارکن ہر قدم کو ایک قطار کے طور پر لکھتے ہیں۔ run_events ٹیبل چلائیں اور پھر پوسٹگریس چلائیں۔ NOTIFY:
export async function appendEvent(
db: Db,
e: { projectId: string; runId?: string; type: string; payload: unknown },
) {
const [row] = await db
.insert(runEvents)
.values(e)
.returning({ id: runEvents.id });
await db.$client.notify(
"events",
JSON.stringify({ projectId: e.projectId, id: row.id }),
);
return row.id;
}
ویب سائڈ پر، Next.js روٹ ہینڈلر ان ایونٹس کو براؤزر میں سٹریم کرنے کے لیے سرور کے بھیجے گئے ایونٹس کا استعمال کرتا ہے۔ جب کوئی براؤزر جڑتا ہے، تو یہ سب سے پہلے ایکٹو رن میں ہر چیز کو دوبارہ چلاتا ہے اور پھر نئی قطاریں وصول کرنا جاری رکھتا ہے۔
const pump = async () => {
const rows = await db
.select()
.from(runEvents)
.where(and(eq(runEvents.projectId, project.id), gt(runEvents.id, cursor)))
.orderBy(asc(runEvents.id));
for (const r of rows) {
cursor = r.id;
send(`id: ${r.id}ndata: ${JSON.stringify(r)}nn`);
}
};
bus.on(project.id, pump); // fired by a single LISTEN connection per process
pump(); // replay first
تمام واقعات ڈیٹابیس میں ہیں، لہذا اگر آپ عملدرآمد کے دوران صفحہ کو ریفریش کرتے ہیں تو آپ کو کچھ بھی نہیں نقصان پہنچے گا۔ براؤزر دوبارہ جوڑتا ہے، اب تک رن کو دوبارہ چلاتا ہے اور جہاں چھوڑا تھا وہیں سے جاری رہتا ہے۔ سٹاپ بٹن اسی طرح مخالف سمت میں کام کرتا ہے۔ ویب ایپ بھیجتی ہے: NOTIFY وہ کارکن جو پھانسی کی شناخت کا استعمال کرتا ہے اور اس پر عمل درآمد کو روکتا ہے۔
میمو: LLM میں سٹریم شدہ ٹیکسٹ ٹوکن کے ذریعہ پیش کیا جاتا ہے، اور ہر ٹوکن کو ذخیرہ کرنے کا مطلب ہے ہر موڑ پر سینکڑوں قطاریں۔ لہذا کارکن اسے بفر کرتا ہے اور اس کے بجائے ہر 250ms پر ایک قطار لکھتا ہے۔ ایک چھوٹا سا بگ بھی تھا جہاں واقعات ترتیب سے باہر ہو جائیں گے کیونکہ ہر تحریر اس کا اپنا وعدہ تھا۔ تمام تحریروں کو ایک ہی وعدے کی زنجیر کے ذریعے آگے بڑھانے سے مسئلہ حل ہوگیا۔
لائیو پیش نظارہ گیٹ وے
تیار کردہ ایپ کا ڈویلپمنٹ سرور پورٹ 5173 پر ایک سینڈ باکس کے اندر چلتا ہے، اور فراہم کنندہ اسے درج ذیل یو آر ایل پر ظاہر کرتا ہے: https://5173-. اب آپ اس URL کو iframe میں ڈال سکتے ہیں اور اسے ایک دن کال کرسکتے ہیں، لیکن اس میں دو مسائل ہیں۔
-
آپ کے براؤزر کو لوڈ کرنے کے لیے ایک سینڈ باکس API کلید کی ضرورت ہوگی۔ ہاں، ظاہر ہے ایسا نہیں ہوتا۔
-
اور اگر ہم اس URL کو عوامی بناتے ہیں، تو جو بھی یو آر ایل کا اندازہ لگاتا ہے وہ اسے کھول سکتا ہے اور ہمارا اس پر کوئی اختیار نہیں ہے کہ کون کیا دیکھتا ہے۔
لہذا ہم نے اس کے سامنے اپنا چھوٹا گیٹ وے بنایا۔ لیڈ اسے دائیں طرف کے سینڈ باکس میں شامل کریں اور سرور کی طرف API کلید شامل کریں۔
const proxy = createProxyServer({ changeOrigin: true, secure: true, ws: true });
const server = http.createServer(async (req, res) => {
const projectId = HOST_RE.exec(req.headers.host ?? "")?.[1];
const target = await resolve(projectId); // project -> sandbox, cached for a few seconds
if (!target.sandboxId) return send(res, noPreviewPage());
delete req.headers.cookie; // never forward the visitor's credentials
delete req.headers.authorization;
proxy.web(req, res, {
target: previewUrlFor(target.sandboxId),
headers: { authorization: `Bearer ${API_KEY}` },
});
});
// Vite's hot reload runs over a WebSocket, so upgrades get proxied too.
server.on("upgrade", async (req, socket, head) => {
const target = await resolve(HOST_RE.exec(req.headers.host ?? "")?.[1]);
proxy.ws(req, socket, head, {
target: previewUrlFor(target.sandboxId).replace(/^https/, "wss"),
headers: { authorization: `Bearer ${API_KEY}` },
});
});
کہ upgrade ہینڈلر وہی ہے جو پیش نظارہ کو زندہ محسوس کرتا ہے۔ جب بھی کوئی ایجنٹ کسی فائل میں ترمیم کرتا ہے، Vite تبدیلیوں کو WebSocket کے ذریعے آگے بڑھاتا ہے اور پیش نظارہ دوبارہ لوڈ کیے بغیر اپ ڈیٹ ہوجاتا ہے۔
ایک اور وجہ ہے جس کی وجہ سے گیٹ ویز آسانی سے چھوٹ جاتے ہیں۔ پیش نظارہ اس پر چلتا ہے: مختلف اصل (*.preview.localhost) مین ایپ (localhost:3000)۔ لہذا، تیار کردہ ایپ مقامی ایپ کی کوکیز کو نہیں پڑھ سکتی ہے یا لاگ ان صارف کے بطور اس کے API کو کال نہیں کر سکتی ہے۔ اور تب سے *.localhost فیصلہ کریں 127.0.0.1 جدید براؤزرز میں آپ کو اس کے لیے میزبان فائل کو چھونے کی بھی ضرورت نہیں ہے۔
میمو: مزید برآں، ٹیمپلیٹ پیش نظارہ میں ایک چھوٹا اسکرپٹ داخل کرتا ہے جو سنتا ہے: window.onerrorپیرنٹ ونڈو پر پوسٹ کریں۔ ورک اسپیس پھر اسے بیک اینڈ پر منتقل کرتا ہے، جہاں ایجنٹ get_browser_errors ٹول کو رن ٹائم کی اصل خرابی ملتی ہے۔
Git کے ساتھ ورژن
ہر مکمل پرامپٹ ایک ورژن بن جاتا ہے۔ یہ صارف کو تقریبا ایک مخصوص "پرامپٹ” پر واپس جانے کی اجازت دیتا ہے جیسے: git reset.
اس مقصد کے لیے، سینڈ باکس کے اندر روایتی گٹ بہت اچھا کام کرتا ہے۔ پہلے سے طے شدہ اسنیپ شاٹ میں پہلے سے ہی پہلی کمٹ کے طور پر ٹیمپلیٹ کے ساتھ ایک ذخیرہ ہوتا ہے، اور ہر کامیاب موڑ کے ساتھ کارکن سب کچھ کرتا ہے۔
export async function commitAll(ps: ProjectSandbox, message: string) {
const out = await git(
ps,
`git add -A
if git diff --cached --quiet; then
echo NOCHANGE
else
git commit -q -m "$MSG"
git rev-parse HEAD
git show --name-only --format= HEAD
fi`,
{ MSG: message },
);
if (out.trim() === "NOCHANGE") return null;
const [sha, ...files] = out.trim().split("n");
return { sha, files };
}
میمو: آپ سوچ رہے ہوں گے کہ ایک کیوں نہیں ہے۔ exit 0 وہاں۔ سے احکام چلتے ہیں۔ bash -lاور واضح exit لاگ ان شیل سے چلائیں۔ ~/.bash_logoutاس تصویر میں، آخری کمانڈ ناکام ہو گئی، ایگزٹ کوڈ کو ناکام میں تبدیل کرنا۔ ایمانداری سے یہ معلوم کرنے میں مجھے زیادہ وقت لگا۔
بحال کرنے سے آپ کی تاریخ دوبارہ نہیں لکھی جائے گی۔ فائل کو بالکل پچھلی کمٹ کی طرح بنائیں، پھر اسے نئے ورژن کی طرح کمٹ کریں۔ لہذا "ریسٹور ورژن 1” ورژن 5 بناتا ہے، اور آپ جب چاہیں ورژن 4 پر واپس جا سکتے ہیں۔ آپ کچھ نہیں کھوتے۔
تاریخ کی استقامت کو برقرار رکھیں (سینڈ باکس میں کوئی ٹوکن نہیں)
سینڈ باکس کے اندر گٹ بہت اچھا ہے، لیکن یہ صرف اس وقت تک چلتا ہے جب تک سینڈ باکس چل رہا ہو۔ لہذا، ہر ورژن کے بعد، تاریخ کو میزبان Git ذخیرہ میں بھی دھکیل دیا جاتا ہے۔
ایسا کرنے کا ایک آسان طریقہ یہ ہے کہ سینڈ باکس کو گٹ ٹوکن فراہم کریں اور چلائیں: git push. لیکن ٹوکنز کی جس حد تک میری رسائی ہے وہ یہ ہے: پورے منصوبےیہ ایک ذخیرہ نہیں ہے۔ کیا آپ ان میں سے ایک کو ناقابل اعتماد کوڈ سے بھرے سینڈ باکس میں ڈالیں گے؟ ہاں، نہیں۔ شکریہ
لہذا سینڈ باکس کچھ بھی نہیں دھکیلتا ہے۔ کہ git bundle (بنیادی طور پر ایک فائل کا پورا ذخیرہ) کارکن اس فائل کو پڑھتا ہے اور کارکن خود ہی دھکا دیتا ہے۔
export async function pushToHostedGit(
ps: ProjectSandbox,
repo: string,
dataDir: string,
) {
await git(ps, "git bundle create -q /tmp/repo.bundle main");
const bundle = await ps.sb.readFile("/tmp/repo.bundle");
const mirror = join(dataDir, "git", `${repo}.git`); // a bare repo on the worker
writeFileSync(join(mirror, "incoming.bundle"), bundle);
await run("git", [
"-C",
mirror,
"fetch",
"-q",
"--force",
"incoming.bundle",
"+refs/heads/main:refs/heads/main",
]);
const cred = await repos.credential(repo); // short lived token, only on the worker
await run("git", [
"-C",
mirror,
"-c",
`http.extraHeader=Authorization: Basic ${basic(cred)}`,
"push",
"-q",
"--force",
url,
"main",
]);
}
اس کا ایک اچھا ضمنی اثر یہ ہے کہ یہ آپ کو طاقت بھی دیتا ہے۔ ریمکس. جب کوئی مشترکہ پروجیکٹ کاپی کرتا ہے، تو کارکن میزبانی کے ذخیرے سے سورس پروجیکٹ بنڈل کو نئے سینڈ باکس میں لوڈ کرتا ہے، اور اس کے لیے اصل سینڈ باکس کو جگانے کی بھی ضرورت نہیں ہوتی ہے۔
سوئیں، جاگیں اور سینڈ باکس کا اشتراک کریں۔
چلنے والے سینڈ باکس پر پیسے خرچ ہوتے ہیں یہاں تک کہ جب کوئی اس پر کام نہیں کر رہا ہوتا ہے۔ لہذا ہمارے پاس ایک چھوٹا سا کام ہے جو ہر منٹ چلتا ہے اور اگر ایجنٹ 10 منٹ تک نہیں چلا تو سینڈ باکس کو معطل کر دیتا ہے۔ معطلی میموری کو محفوظ رکھتی ہے اور آپ کے ڈویلپمنٹ سرور کو بالکل اسی طرح واپس لاتی ہے جیسا کہ تھا۔
بیداری گیٹ وے پر ہوتی ہے۔ جب کوئی کسی نیند کے پروجیکٹ کا پیش نظارہ کھولتا ہے، تو گیٹ وے تھوڑا سا "ویک اپ ایپ…” صفحہ دکھاتا ہے جو پس منظر میں سینڈ باکس کو مسلسل ریفریش اور دوبارہ شروع کرتا ہے۔
if (isPage && target.status === "suspended") {
const outcome = wake(projectId, target, log); // deduplicated per project
const done = await Promise.race([outcome, timeout(4000, "pending")]);
if (done === "busy") return send(res, busyPage());
if (done !== "running") return send(res, wakingPage()); // auto refreshes
}
میری جانچ میں، سوئے ہوئے سینڈ باکس تقریباً 3 سیکنڈ میں بیدار ہو گئے اور ایپ فوراً لوڈ ہو گئی۔
مشترکہ سینڈ باکسز کی محدود تعداد
زیادہ تر سینڈ باکس فراہم کرنے والے، خاص طور پر مفت پلانز پر، سینڈ باکسز کی تعداد کو محدود کرتے ہیں جو آپ بیک وقت چلا سکتے ہیں۔ لہذا میں نے ایک چھوٹا کنکرنسی چیکر شامل کیا اور یہ سب پوسٹگریس میں ایڈوائزری لاکنگ کے ساتھ ہوتا ہے لہذا کوئی بھی دو کارکن ایک ہی وقت میں ایک ہی فیصلہ نہیں کرتے ہیں۔
async function decide(db: Db, projectId: string) {
return db.transaction(async (tx) => {
await tx.execute(sql`select pg_advisory_xact_lock(${LOCK_KEY})`);
const live = await runningSandboxesOldestFirst(tx);
if (live.some((s) => s.projectId === projectId)) return { kind: "ok" };
if (live.length < concurrencyLimit()) return { kind: "ok" };
// Full. Free a slot by suspending the least recently used idle sandbox.
const victim = live.find((s) => !busyProjects.has(s.projectId));
if (victim) return { kind: "evict", sandboxId: victim.sandboxId };
return { kind: "wait", position }; // everything is busy, just wait...
});
}
اس کی جانچ کرنے کے لیے، ہم نے حد کو 1 پر سیٹ کیا اور ایک پروجیکٹ کا اشارہ کیا جب کہ دوسرے پروجیکٹ کا سینڈ باکس بیکار تھا۔ بیکار حالت نیند میں چلی گئی اور ایک نئی چیز نے اس سلاٹ کو لے لیا۔ اس کے بعد میں نے پہلے پروجیکٹ کو ایک پرامپٹ بھیجا جبکہ دوسرا پروجیکٹ ابھی بھی کام کر رہا تھا، اور UI نے سلاٹ دستیاب ہونے تک "مفت سینڈ باکس کا انتظار، #1 لائن میں” دکھایا۔ اگر آپ کے پاس بڑے منصوبے ہیں، تو آپ صرف حد بڑھا سکتے ہیں۔ .env اس کے علاوہ کچھ نہیں بدلتا۔
اپنی ایپ شائع کریں۔
تعمیر کے دوران پیش نظارہ کرنا بہت اچھا ہے، لیکن میں نہیں چاہتا کہ میری شائع شدہ ایپ کسی ایسے سینڈ باکس پر انحصار کرے جو ہر 10 منٹ بعد سلیپ موڈ میں چلا جائے۔
لہذا اشاعت آپ کی ایپ کو ایک بار بنائے گی اور اسے باقاعدہ جامد فائل میں تبدیل کردے گی۔
export async function publish(project: Project) {
const ps = await projectSandbox(project.id); // wakes it if needed
const build = await ps.exec(
"rm -rf dist && npx vite build --outDir dist --emptyOutDir 2>&1",
{ timeoutSecs: 180 },
);
if (build.exitCode !== 0)
throw new HttpError(422, `The build failed:n${build.stdout.slice(-1500)}`);
const files = await listFiles(ps, "dist");
const prefix = `published/${slug}/${versionId}/`;
for (const f of files) {
const bytes = await ps.readBytes(`dist/${f}`);
await storage.put(prefix + f, bytes, contentTypeFor(f), cacheControlFor(f));
}
await savePublishedSite({ projectId: project.id, slug, s3Prefix: prefix });
return { url: publishedUrl(slug) };
}
گیٹ وے پھر S3 سے ان فائلوں کی خدمت کرتا ہے۔ http://. فائلیں جو Vite ہیش کرتی ہیں، جیسے assets/index-CScgwd68.js) ہمیشہ کے لیے کیش ہو جائے گا۔ index.html اس کی ہمیشہ دوبارہ تصدیق کی جاتی ہے، لہذا آپ کو فوری طور پر اپ ڈیٹس نظر آئیں گے۔ فائل ایکسٹینشن کے بغیر تمام راستے اس کے ساتھ تبدیل کردیئے گئے ہیں: index.htmlلہذا کلائنٹ سائیڈ روٹنگ بھی کام کرتی ہے۔
اور شائع شدہ سائٹ کا جان بوجھ کر اپنا ذیلی ڈومین ہے۔ اگر یہ آپ کے مرکزی ایپ کے ڈومین کے تحت ہے، تو آپ کی شائع شدہ ایپ میں موجود JavaScript اسے دیکھنے والے شخص کی کوکیز کا استعمال کرتے ہوئے آپ کے API کو کال کر سکتا ہے، اور آپ واقعی ایسا نہیں چاہتے ہیں۔
میری جانچ میں، اشاعت میں تقریباً 6 سیکنڈ لگے اور شائع شدہ سائٹ سینڈ باکس لاک کے ساتھ 4ms میں لوڈ ہو گئی کیونکہ اس نے کبھی بھی سینڈ باکس کو ہاتھ نہیں لگایا۔
ایکشن میں ایپ بلڈر
عمل میں ایپ بلڈر کا ایک فوری ڈیمو یہ ہے:
میں نے تجسس کی وجہ سے ایک چھوٹی سی تشخیص بھی کی۔ نئے سینڈ باکس میں وہی تین پرامپٹس (ہیبیٹ ٹریکر، کنبن بورڈ، اور چارٹس کے ساتھ لاگت کا ڈیش بورڈ) ہر دو ماڈل کو بھیجیں۔
| ماڈل | پاس کیا گیا (تعمیر + رینڈر) | اوسط وقت |
|---|---|---|
| کلاڈ سونیٹ 5 | 3/3 | 135 سیکنڈ |
| GPT 5.5 | 3/3 | 92 کی دہائی |
تمام چھ ایپس نے بغیر کسی ترمیم کے پہلے معائنہ پر بنایا اور پیش کیا، جس نے ایمانداری سے مجھے تھوڑا سا حیران کردیا۔ کلاڈ پر، ہر ایپ کی قیمت تقریباً $0.15 سے $0.20 ہے۔
نتیجہ
تو آپ اس منصوبے کے بارے میں کیا سوچتے ہیں؟ AI نے خام کوڈنگ کی جگہ لینے کے بعد سے یہ سب سے زیادہ تفریحی پروجیکٹس میں سے ایک رہا ہے جس پر میں نے تھوڑی دیر میں کام کیا ہے۔
Lovable جیسے ٹولز کے ساتھ، یہ سوچنا آسان ہے کہ اشارے اور ماڈل ہی سب کچھ ہیں۔ لیکن ایک بار جب آپ اسے خود بناتے ہیں، تو آپ کو احساس ہوتا ہے کہ زیادہ تر کام ماڈل کے ساتھ ہوتا ہے: کوڈ کہاں سے چلتا ہے، یہ کتنی تیزی سے شروع ہوتا ہے، یہ صارف کو کیسے ظاہر ہوتا ہے، اور آپ اسے ایسے کام کرنے سے کیسے روکتے ہیں جو اسے نہیں کرنا چاہیے۔
اگر میں یہاں ایک چیز پر زور دینا چاہتا ہوں تو وہ سینڈ باکس کا حصہ ہے۔ AI سے تیار کردہ کوڈ کو ناقابل اعتماد سمجھیں اور اسے اس کا اپنا کمپیکٹ سسٹم دیں جس میں کوئی راز نہیں ہے اور نیٹ ورک تک رسائی کم ہے۔ میموری اسنیپ شاٹس اور معطل/ریزیوم تیز اور سستی پروسیسنگ کو قابل بناتے ہیں۔
اب بھی توسیع کی بہت گنجائش ہے۔ آپ اپنے ٹیمپلیٹس میں چھوٹے بیک اینڈز (جیسے Hono اور SQLite) شامل کر سکتے ہیں تاکہ صارفین کو مکمل اسٹیک ایپس بنانے کی اجازت دی جا سکے، صارفین کو ان اجزاء کو درست طریقے سے ترمیم کرنے کے لیے پیش نظارہ میں موجود عناصر پر کلک کرنے کی اجازت دیں، یا ایک ہی پرامپٹ کے ساتھ ساتھ کئی ڈیزائن کی مختلف حالتیں تخلیق کریں۔ میں اب اسے لاگو کرنے کے لئے بہت تھک گیا ہوں. میں اسے تم پر چھوڑ دوں گا۔
بنیاد وہیں ہے۔ باقی صرف اس کے اوپر تعمیر کر رہا ہے.
آپ کو مکمل سورس کوڈ یہاں مل سکتا ہے: shricodev/lovable-build-tensorlake-aws
اس مضمون کے بارے میں یہی ہے۔ پڑھنے کے لیے آپ کا بہت شکریہ! اگلی بار ملتے ہیں۔