DeepSeek Harness-এর জন্য নিজের dsh plugin লিখুন
খালি folder থেকে dsh plugin তৈরি শিখুন: package.json-এর জরুরি field, plugin mount করার patch file, বাস্তব tool এবং প্রয়োজনীয় দুই hook-এর সম্পূর্ণ উদাহরণ।
DeepSeek Harness plugin আসলে কী
একটি dsh plugin হলো এমন একটি npm package, যা একটি apply function export করে এবং একটি ছোট YAML file অন্তর্ভুক্ত করে। এই file-এর মাধ্যমে DeepSeek Harness-কে plugin-টি load করতে বলা হয়। আগে আলাদা কোনো plugin SDK শেখার প্রয়োজন নেই। dsh একটি Cordis application, এবং “everything is a plugin” কথাটি আক্ষরিক অর্থেই প্রযোজ্য: tool registry, agent loop, session store এবং web server—সবই একই plugin tree-এর node, যেখানে আপনার package যুক্ত হয়।
Cordis একটি সাধারণ composition framework। এটি স্বাধীনভাবে তৈরি হয়েছে এবং বহু বছর ধরে Koishi chatbot framework-এর ভিত্তি হিসেবে ব্যবহৃত হচ্ছে। এটি plugin load ও unload করে এবং plugin-গুলোর পারস্পরিক dependency resolve করে। Cordis agent সম্পর্কে কিছু জানে না। Agent-সংক্রান্ত সবকিছু এর ওপর বসানো harness package থেকে আসে। তাই নিচের plugin structure এত ছোট দেখায়। আপনি যে functionality পান, তার বেশিরভাগই inherited।
একটি plugin-এর দুটি অংশ থাকে। Host অংশটি Node-এ চলে, tool ও event listener register করে এবং নিজস্ব service প্রদান করতে পারে। Browser অংশটি Web UI-এর মধ্যে চলে এবং interface slot register করে। প্রথম plugin প্রায় সবসময় host-only হয়। তাই প্রয়োজন না হওয়া পর্যন্ত browser অংশকে optional হিসেবে বিবেচনা করুন।
এই guide-টি @deepseek-ai/dsh version 0.1.0-rc.7, অর্থাৎ 19 August 2026-এর npm latest tag অনুযায়ী লেখা হয়েছে। dsh একটি developer preview, এবং এর README-তে বলা আছে যে compatibility ভেঙে দিতে পারে এমন পরিবর্তন আসবে। নিচের প্রতিটি key name ওই তারিখে upstream documentation ও repository থেকে যাচাই করা হয়েছে। কোনো key-এর ওপর নির্ভর করার আগে আবার যাচাই করুন, কারণ preview API release candidate-গুলোর মধ্যে field-এর নাম পরিবর্তন করতে পারে। Harness এখনও চালু না থাকলে প্রথমে VPS-এ DeepSeek Harness এবং dsh API key ও model configuration সেট up করুন। এরপর এখানে ফিরে আসুন।
কোনো কিছু package করার আগে একটি scratch file load করুন
প্রথমে package করা শেখার ধীর পদ্ধতি। একটি file load করুন, runtime আপনার code call করছে কি না নিশ্চিত করুন, তারপর package করুন।
harness checkout-এর বাইরে একটি folder তৈরি করুন এবং তাতে একটি file রাখুন।
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) {
console.log('[hello-plugin] plugin loaded')
}export const name হলো diagnostics-এ plugin শনাক্ত করার metadata। apply হলো সম্পূর্ণ contract: Cordis এটিকে একবার call করে এবং আপনার plugin-এর scope-এ থাকা একটি context পাঠায়। ওই context-এ আপনি যা register করবেন, plugin dispose হলে Cordis তা আপনার হয়ে সরিয়ে দেবে।
এর পাশে cordis.yml লিখুন।
- insert:
- id: hello
name: '/absolute/path/to/scratch-plugin/hello.ts'এখন ওই file-টিকে উপরে layer করে একটি profile boot করুন।
dsh web --patch ./scratch-plugin/cordis.ymlআপনার PATH-এ dsh না থাকলে npx @deepseek-ai/dsh web --patch ./scratch-plugin/cordis.yml একই কাজ করে। এই npx পদ্ধতিতে এই guide-এ বর্ণিত version-এর বদলে cached পুরোনো release candidate পাওয়া যেতে পারে। তাই harness কোনো documented flag সরাসরি reject করলে নিজের file নিয়ে সন্দেহ করার আগে dsh install এবং version error-এর সমাধানগুলো অনুসরণ করুন। dsh চালু করা terminal-এ [hello-plugin] plugin loaded দেখতে পাওয়ার কথা। কিছু দেখা না গেলে row resolve হয়নি।
name field-এ npm package name অথবা filesystem path দেওয়া যায়। upstream documentation অনুযায়ী path-টি absolute হতে হবে। scratch plugin কোনো output না দিলে প্রথমে relative ./hello.ts পরীক্ষা করুন। দ্বিতীয় বিষয় হলো file extension। harness repository-এর clone থেকে documented loop-টি pnpm dsh web --patch ... হিসেবে run হয়। সেখানে TypeScript entry-গুলো tsx-এর মাধ্যমে load হয়। আপনার dsh যদি npm থেকে আসে, row-টিকে plain JavaScript file-এ point করুন, অথবা আগে file build করুন।
--patch হলো launcher flag। এর overlay সব bundle এবং আপনার নিজের profile patch-এর পরে, শেষে apply হয়। তাই iteration করার সময় scratch overlay সবসময় কার্যকর থাকে, যা এই পর্যায়ে আপনার প্রয়োজন।
যে টুলটি উপকারী কাজ করে, সেটিই সবচেয়ে ছোট করে লিখুন
একটি log line প্রমাণ করে যে plugin লোড হয়েছে। একটি tool প্রমাণ করে যে plugin agent-এর অংশ।
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'
export const inject = ['tools']
export function apply(ctx: Context) {
ctx.tools.register(defineTool({
name: 'greet',
description: 'Greet someone by name.',
parameters: {
name: { type: 'string', required: true, description: 'The name to greet' },
},
output: {
schema: { type: 'string' },
render: (_args, value) => [{ type: 'text', text: value }],
},
async execute(args) {
return `Hello, ${args.name}!`
},
}))
}export const inject = ['tools'] হলো সেই line, যা অনেকে বাদ দেন। Cordis configuration-এর entry-গুলো একই সময়ে start হয়। তাই file-এ কোনো row-এর অবস্থান load order নিশ্চিত করে না। Ordering নির্ধারিত হয় ঘোষিত dependency দিয়ে। inject Cordis-কে ctx.tools তৈরি না হওয়া পর্যন্ত অপেক্ষা করতে বলে। এরপরই এটি আপনার apply call করে। এটি না থাকলে registry register করার আগেই আপনার code চলতে পারে।
Object-এর বাকি অংশ model যে contract দেখে, সেটি নির্ধারণ করে। parameters হলো argument schema। execute এমন argument পায়, যা ইতিমধ্যে ওই schema অনুযায়ী parse করা হয়েছে। output.schema, execute যে value return করে, সেটি বর্ণনা করে। আর render ওই value-কে model যে content block পড়ে, তাতে রূপান্তর করে। এই দুটিকে আলাদা রাখলেই interface এক জিনিস দেখাতে পারে, আর model অন্য জিনিস পড়তে পারে।
Profile start করুন এবং assistant-কে নাম ধরে কাউকে greeting জানাতে বলুন। Reply আপনার execute-এর মাধ্যমে ফিরে আসে। ctx দিয়ে registration reversible, তাই plugin dispose করলে tool-টি আপনার হয়ে unregister হয়ে যায়। Cordis যে resource সম্পর্কে জানতে পারে না, যেমন socket বা file handle, সেগুলোর জন্য ctx.effect() call করুন এবং সেখানে একটি disposer দিন।
প্রথম plugin যে দুটি extension point-এ সত্যিই কাজ করে
সম্পূর্ণ seam-এর তালিকা দীর্ঘ। প্রথম plugin-এর প্রায় সব কাজ এই দুটির মধ্যেই পড়ে।
Conversation event হলো স্থায়ী, log করা stream। নামগুলো হলো session/event, turn/start, turn/end, step/start, step/end, user/message, assistant/message, assistant/chunk, tool/call এবং tool/result। এখানে একটি সাধারণ listener সংযুক্ত করুন।
ctx.on('tool/call', (payload) => {
console.log('[my-plugin] tool/call', JSON.stringify(payload))
})Payload একবার print করে পড়ুন। কোনো guide থেকে, এমনকি এই guide থেকেও, payload field-এর নাম কপি করবেন না, কারণ preview API-তে payload-এর গঠনই সবচেয়ে বেশি পরিবর্তিত হয়।
দ্বিতীয় extension point হলো waterfall। agent/pre-step, agent/request, agent/request-error, llm/stream এবং tools/* event হলো waterfall, আর waterfall listener-এর signature আলাদা। এটি একটি next callback গ্রহণ করে, এবং listener callback-টি call করলেই কেবল chain এগোয়।
ctx.on('agent/request', async (payload, next) => {
const startedAt = Date.now()
const downstream = await next()
console.log('[my-plugin] model request took', Date.now() - startedAt, 'ms')
return downstream
})await next() ভুলে গেলে hook যোগ হয় না। আপনি model call-টিকে কোনো ফল ছাড়াই প্রতিস্থাপন করেছেন, তাই agent সেখানেই থেমে যায়। কোনো gateway plugin ইচ্ছাকৃতভাবে request প্রত্যাখ্যান করলে short circuit করাই নকশা অনুযায়ী আচরণ। এই এক পার্থক্যই প্রথম plugin নিয়ে বেশিরভাগ বিভ্রান্তির কারণ। এর চারপাশে অন্য কিছু লেখার আগে next() call লিখুন।
agent/request নিজেই model call-টিকে wrap করে। এর payload-এ call করা agent, চলমান turn-এর নম্বর, request-টি যে step-এর অন্তর্ভুক্ত এবং সেই turn-এর abort signal থাকে। তাই request logger বা rate limiter-এর জন্য এটিই উপযুক্ত seam। tools/* waterfall একই গঠনের, তবে এক স্তর নিচে কাজ করে। tools/pre-execute dispatch-এর আগে অনুমতি দেয়, প্রত্যাখ্যান করে অথবা approval চায়। tools/execute dispatch-কে wrap করে। tools/post-execute normalised result প্রতিস্থাপন বা block করতে পারে। tools/result শুধু স্থির হয়ে যাওয়া outcome পর্যবেক্ষণ করে।
অন্যরা ইনস্টল করতে পারে এমন bundle হিসেবে প্যাকেজ করুন
একটি bundle হলো এমন একটি npm package, যার package.json-এ একটি dsh.bundle field থাকে এবং সেটি তার patch file-এর দিকে নির্দেশ করে। এই declaration-ই scratch file এবং ইনস্টলযোগ্য package-এর মধ্যে সম্পূর্ণ পার্থক্য তৈরি করে।
{
"name": "dsh-plugin-hello",
"version": "0.1.0",
"type": "module",
"main": "lib/index.js",
"files": ["lib", "cordis.patch.yml", "README.md", "LICENSE"],
"engines": { "node": "^22.19 || >=24", "dsh": ">=0.1.0-rc.6" },
"dsh": { "bundle": { "patch": "./cordis.patch.yml" } },
"keywords": ["dsh-plugin", "deepseek-harness"],
"scripts": { "build": "tsdown", "prepare": "pnpm run build" },
"exports": {
".": { "types": "./lib/index.d.ts", "default": "./lib/index.js" },
"./cordis.patch.yml": "./cordis.patch.yml",
"./package.json": "./package.json"
}
}এর পাশে থাকা cordis.patch.yml সংক্ষিপ্ত।
- insert:
- id: dsh-plugin-hello
name: dsh-plugin-helloname row-তে package name থাকে, তাই দুটি string অবশ্যই একই হতে হবে। id row-কে পরবর্তী কোনো layer ব্যবহারকারী আপনার configuration override করলে target করে। তাই একটি স্থিতিশীল নাম বেছে নিন এবং এটি অন্য কোনো plugin-এর জন্য পুনরায় ব্যবহার করবেন না।
files-এ cordis.patch.yml অবশ্যই তালিকাভুক্ত থাকতে হবে। এটি বাদ দিলে প্রকাশিত tarball-এ এমন একটি dsh.bundle.patch থাকে, যা কখনো প্যাক করা হয়নি। ফলে package ইনস্টল হলেও tree-তে কোনো অবদান রাখে না।
আপনার plugin folder থাকা directory থেকে এটি একটি profile-এ ইনস্টল করুন।
dsh plugin --profile demo add ./dsh-plugin-hello
dsh --profile demo --dump-config
dsh --profile demodsh plugin --profile <name> তার বাকি arguments ওই profile directory-এর ভিতরে pnpm-এ পাঠায়। তাই add এবং remove pnpm-এর মতোই কাজ করে। dsh plugin --profile demo remove dsh-plugin-hello দিয়ে uninstall করুন। web এবং headless profile প্রথমবার ব্যবহার করার সময় shipped template থেকে নিজে তৈরি হয়। অন্য যেকোনো profile name dsh plugin-এর মাধ্যমে তৈরি করতে হবে।
composed tree-এ আপনার row অনুপস্থিত কেন
Composition একটি খালি entry list থেকে শুরু হয় এবং layer-গুলো নির্দিষ্ট ক্রমে যোগ করে। Profile-এর dsh.profile.bundles-এ তালিকাভুক্ত প্রতিটি bundle, তালিকার ক্রম অনুযায়ী। এরপর profile-এর নিজস্ব cordis.patch.yml। তারপর $DSH_HOME/cordis.patch.yml। সবশেষে command line থেকে দেওয়া যেকোনো --patch overlay। পরের layer-গুলো id অনুযায়ী আগের row প্রতিস্থাপন করে।
Profile-গুলো $DSH_HOME/profiles/<name>-এর অধীনে থাকে। একটি profile directory-তে package.json থাকে, যেখানে dsh.profile manifest এবং তার সাজানো bundles list থাকে। একই directory-তে ব্যবহারকারীর নিজস্ব patch file-ও থাকে। Bundle name প্রথমে dsh installation থেকে এবং পরে profile-এর node_modules থেকে resolve হয়। pnpm out-of-tree plugin এখানে রাখে।
dsh --profile demo --dump-config কোনো কিছু boot না করেই সম্পূর্ণ composed tree দেখায়। Debugging-এর জন্য এটিই বিভাজনরেখা। আপনার row id অনুপস্থিত হলে সমস্যা composition-এ: কোনো name resolve হচ্ছে না, অথবা কোনো patch file কখনো pack করা হয়নি। Row উপস্থিত থাকা সত্ত্বেও কিছু না ঘটলে সমস্যা আপনার code-এ। আগে এই প্রশ্নের উত্তর দিন। এতে অধিকাংশ অনুমানভিত্তিক troubleshooting এড়ানো যায়।
লোডিং-সংক্রান্ত ত্রুটি আসলে কোথায় দেখা যায়
apply-এর ভেতরে ছোড়া কোনো ত্রুটি স্পষ্টভাবে দেখা যায়। সেই exception-এর কারণে process বন্ধ হয়ে যায় এবং আপনার নিজের line-এ নির্দেশ করা একটি stack trace পান।
Resolution failure সাধারণত নীরবে ঘটে। Loader যে module resolve করতে পারে না, সেটি crash না করে Cordis logger-এর মাধ্যমে জানায়। Upstream tutorial-এ সতর্ক করা হয়েছে যে startup-এর সময় এই message হারিয়ে যেতে পারে, কারণ console exporter সংযুক্ত হওয়ার আগেই এগুলো নির্গত হয়। তাই path-এর typo এমন দেখায়, যেন plugin load হয়েছে কিন্তু কোনো কাজ করছে না। এই কারণেই কোনো code পড়ার আগে উপরের --dump-config check চালানো উপযোগী।
Development-এর সময় apply-এর প্রথম statement হিসেবে একটি console.log রাখুন। এটি না থাকলে সমস্যার কোন অর্ধে ত্রুটি রয়েছে তা বোঝা যায়। পরে এটি মুছে ফেলতে কোনো সমস্যা নেই। Server-এ কাজ করার সময় harness-টি service manager-এর অধীনে না চালিয়ে foreground-এ চালান। এতে loader-এর output সরাসরি terminal-এ দেখা যায়। Journal পড়তে আলাদা করে যেতে হয় না।
পৃথিবীর সবকিছু পুনরায় চালু না করেই পরিবর্তন প্রয়োগ
আজ host অংশের জন্য সৎ উত্তর হলো: restart করুন। Web application bundle-এর shared hot module reload ব্যবস্থা নিষ্ক্রিয় অবস্থায় প্রকাশিত হয়। ফাইলটিতে উল্লেখ আছে, reload lifecycle পরীক্ষা করা হলে এটি আবার সক্রিয় করা হবে। Client-side reload chain সব সময় mounted থাকে, কিন্তু rebuild watcher client bundle নতুন করে লিখে না দেওয়া পর্যন্ত idle অবস্থায় থাকে। তাই আপনার Node অংশেও এটি কোনো কাজ করে না।
এখনো নেই এমন reload ব্যবস্থা খোঁজার পরিবর্তে restart দ্রুত ও সহজ করুন। Plugin-টি একটি ফাইলেই রাখুন। Profile-এ install না করে --patch দিয়ে load করুন। এতে edit এবং run-এর মাঝখানে কোনো build step বা pnpm step থাকে না। ctx-এর মাধ্যমে সবকিছু register করুন। তাহলে restart-এর পরে duplicate tool বা পুরোনো listener থেকে যাবে না। নিজে allocate করা যেকোনো resource ctx.effect()-এর মধ্যে একটি কার্যকর disposer-সহ wrap করুন। Disposer না থাকার সাধারণ লক্ষণ হলো, প্রথম run যে port ধরে রেখেছে সেটিতেই দ্বিতীয় run ব্যর্থ হওয়া।
আপনি যদি নিজের laptop-এর পরিবর্তে কোনো server-এ চলমান harness-এর বিরুদ্ধে develop করেন, ওপরের কোনো বিষয়ই বদলাবে না। তবে Web UI binding গুরুত্বপূর্ণ। port 3080-এ loopback bind ব্যাখ্যা করে কেন page নিজে থেকে open হয় না এবং এ ক্ষেত্রে কী করতে হবে।
ব্রাউজার অংশ এবং এটিকে কতটা বিশ্বাস করবেন
আপনার plugin-এর নিজস্ব interface প্রয়োজন হলেই এটি যোগ করুন। এটি bundle-এর মতো একই dsh field-এ declared হয়।
{
"dsh": {
"client": {
"platform": "web",
"inject": [],
"external": [],
"immediately": false
}
},
"exports": {
".": "./src/index.ts",
"./client": "./src/client/apply.ts",
"./package.json": "./package.json"
}
}"platform": "web" আবশ্যক। Package-এ ./client export না থাকলে scanner error দেয়। তাই export map কোনো সুবিধামাত্র নয়; এটি manifest-এর অংশ। Client entry-তে Cordis Context-এর সঙ্গে client runtime type যোগ করা হয়। প্রতিটি registration apply-এর মধ্যে ctx.slots.register ব্যবহার করে সম্পন্ন করতে হয়। সেখানে module-level side effect অনুমোদিত নয়।
import type { Context } from 'cordis'
import type { DshClientContext } from '@deepseek-ai/dsh-client-runtime'
export async function apply(ctx: Context & DshClientContext) {
ctx.slots.register({ name: 'domain.entry.slot' }, MyComponent)
}শুরু করার আগে দুটি বিষয় জানা দরকার। Client manifest-এর inject scheduling নিয়ন্ত্রণ করে না; এটি documentation হিসেবে package-level dependency edge নথিবদ্ধ করে। Baseline-এর বাইরে module request ঘোষণা করতে external ব্যবহার করুন, যাতে আপনার plugin সেগুলোর অনুরোধ করার আগেই সেগুলো materialise করা হয়। Preview-এর এই অংশে দ্রুত পরিবর্তন হচ্ছে। তাই code লেখার দিন harness repository-র packages/client/AGENTS.md পড়ুন, কোনো guide পড়ার দিন সেটির ওপর নির্ভর করবেন না।
প্রকাশ করুন, এবং আপনার plugin কী স্পর্শ করে তা জানান
একটি GitHub repository-তে dsh-plugin topic যোগ করলে plugin খুঁজতে আসা মানুষ যে তালিকাটি দেখেন, সেখানে এটি যুক্ত হয়। এটি অপরিচিত মানুষের আস্থার ওপর দাবি তৈরি করে এবং এর সঙ্গে কিছু দায়িত্বও আসে। এই দায়িত্বগুলো পাঠকদের জন্য আমাদের dsh plugin ইনস্টল করার আগে যাচাই করার নির্দেশিকা-তে উল্লেখ করা বিষয়গুলোরই বিপরীত প্রতিফলন। তাই সেই checklist অনুসরণ করাই এটি পাস করানোর সবচেয়ে সহজ উপায়।
- Dependency pin করুন। Transitive dependency-তে caret range ব্যবহার করলে গত সপ্তাহে নিরাপদ থাকা package এই সপ্তাহে ভিন্ন code চালাতে পারে। server-এ npm supply chain attack-এর পেছনে ঠিক এই প্রক্রিয়াই কাজ করে।
- Manifest-এ আপনি কী স্পর্শ করেন তা উল্লেখ করুন। আপনার
injectlist হলো কোন harness service আপনি গ্রহণ করেন তার একটি সঠিক, machine-readable সারাংশ। Reviewer কয়েক সেকেন্ডেই এটি পড়ে আপনার plugin সম্পর্কে ধারণা তৈরি করেন। - নীরবে network call করবেন না। কোনো tool API call করলে README-তে host-এর নাম দিন এবং endpoint configurable করুন। যে plugin উল্লেখ না করা কোনো server-এর সঙ্গে যোগাযোগ করে, এসব বিষয় audit করা ব্যক্তিরা সেটিকে তালিকা থেকে সরিয়ে দেবেন।
filesসীমিত রাখুন। পুরো working folder publish করলে অসাবধানতায় কোনো credential file registry-তে পৌঁছে যেতে পারে।- Git installer-দের এমন একটি
preparescript দিন, যা শুধু development-এর জন্য প্রয়োজনীয় assumption ছাড়াই build হয়। README-তে জানান যে তাদের profile-এরpnpm-workspace.yaml-এ ওই build allowlist করতে হবে। - যে release candidate তৈরি ও পরীক্ষা করেছেন, তার সঙ্গে মিল রেখে README-তে date stamp দিন। Preview API ব্যবহারকারী পাঠকদের জানতে হবে আপনি কোন version ব্যবহার করেছিলেন।
একটি সম্পূর্ণ plugin বাইরে থেকে কেমন দেখায় তা জানতে ইনস্টল করার মতো dsh plugin পড়ুন এবং লক্ষ্য করুন, প্রতিটি README install করার আগে আপনাকে কী জানায়। আপনি যদি অন্য কোনো agent-এর জন্য extension লিখে থাকেন, তাহলে Claude Code plugin কীভাবে তৈরি করা হয় একটি কার্যকর তুলনা। Harness আপনাকে একটি live object graph এবং reversible registration দেয়। এটি files-এর manifest-এর চেয়ে বেশি ক্ষমতা দেয়, এবং সেই সঙ্গে বেশি দায়িত্বও দেয়।
FAQ
dsh plugin লিখতে কি npm-এ publish করতে হবে?
না। cordis.yml overlay-এর একটি filesystem path, dsh web --patch ./scratch-plugin/cordis.yml দিয়ে load করলেই harness-এর ভিতরে আপনার নিজস্ব code চালানো যায়। Path-টি absolute হতে হবে। অন্য কেউ plugin install করলে তবেই packaging গুরুত্বপূর্ণ। সেই ক্ষেত্রেও registry ব্যবহার না করে dsh plugin --profile demo add ./my-plugin দিয়ে local folder install করে packaged form পরীক্ষা করতে পারেন।
আমার plugin load হয়, কিন্তু tool কখনো দেখা যায় না কেন?
প্রথমে dsh --profile demo --dump-config চালান। ওই output-এ আপনার row id না থাকলে plugin mount হয়নি। কারণ code নয়, composition-এ। row থাকলে export const inject = ['tools'] আছে কি না পরীক্ষা করুন। Cordis configuration-এর entry-গুলো একসঙ্গে start হয়। তাই file order load order নির্ধারণ করে না। ওই declaration না থাকলে Cordis tool registry-এর জন্য অপেক্ষা করে না। ফলে আপনার apply এমন সময় চলতে পারে, যখন register করার জন্য ctx.tools available নয়।
cordis.yml এবং cordis.patch.yml-এর মধ্যে পার্থক্য কী?
cordis.yml একটি সম্পূর্ণ entry list। cordis.patch.yml একটি layer, যা এর ওপর প্রয়োগ হয়। এটি id অনুযায়ী row নির্বাচন করে নতুন row যোগ করে অথবা বিদ্যমান configuration প্রতিস্থাপন করে। একটি bundle package.json-এর dsh.bundle.patch ব্যবহার করে নিজের patch file নির্দিষ্ট করে। Layer-গুলো নির্দিষ্ট ক্রমে প্রয়োগ হয়: profile-এ তালিকাভুক্ত ক্রমে প্রতিটি bundle, তারপর profile-এর patch file, তারপর $DSH_HOME/cordis.patch.yml, এবং শেষে যেকোনো --patch overlay। পরের layer-এর configuration কার্যকর হয়।
agent চলার সময় কি dsh plugin hot reload করা যায়?
web profile-এর host অংশের জন্য 0.1.0-rc.7 অনুযায়ী তা যায় না। ওই bundle-এ shared hot module reload row disabled অবস্থায় থাকে। File-এ উল্লেখ আছে, reload lifecycle পরীক্ষা শেষ হলে এটি আবার চালু করা হবে। তাই দ্রুত restart-এর জন্য design করুন। একটি file ব্যবহার করুন, build step ছাড়াই --patch দিয়ে load করুন, এবং প্রতিটি registration ctx দিয়ে করুন, যাতে এক run-এর resource পরের run-এ leak না হয়। Cordis নিজে যেসব resource cleanup করতে পারে না, সেগুলোর জন্য disposer-সহ ctx.effect() ব্যবহার করুন।