Skill: sazidulalam47/teletalk-alljobs-govjob-search (version 1.0.5)

--- name: teletalk-alljobs-govjob-search description: Search Bangladesh government jobs from the Teletalk AllJobs API, filter out excluded keywords, present matching jobs, and track applied job IDs. Use when the user wants gov job search results from alljobs.teletalk.com.bd, wants to exclude roles by keyword, or wants to save applied government job IDs after confirmation. --- # Teletalk AllJobs Gov Job Search Use this skill to search and shortlist government jobs from the Teletalk AllJobs API. ## Core flow 1. Ask the user for: - a search keyword, such as `electrical`, `civil`, `mechanical`, `computer`, or `engineer` - excluded keywords, such as `Sub Assistant`, `Diploma` 2. Save the preferences in `data/preference.json`. 3. Run the search script with the keyword. 4. Show the remaining jobs with only these fields: - `job_title` - `job_title_bn` - `org_name` - `org_name_bn` - `vacancy` - `deadline_date` (show date and BST, Bangladesh Standard Time when possible) - `application_site_url` Skip any jobs whose deadline has already passed. 5. If the user confirms they applied, save the `job_primary_id` in `data/appliedJobIds.json`. ## Data files Store skill data inside this skill folder in: - `data/preference.json` - `data/appliedJobIds.json` Use this preference shape: ```json { "keyboard": "", "excluded": ["", ""] } ``` Note: keep the field name as `keyboard` to match the skill data format, even though it represents the search keyword. ## Confirmation behavior When the user says they applied: - append the `job_primary_id` to `data/appliedJobIds.json` - avoid duplicates ## Script entry point Use the script inside this skill folder: - `scripts/teletalk-alljobs-search.js` The script should: - read `data/preference.json` - call the Teletalk API - filter excluded keywords - skip jobs whose deadline has already passed - print the compact job list as JSON ## Notes - Keep the skill focused on Teletalk government jobs only. - Do not mix this workflow with BDJobs skill data. - Favor deterministic filtering over model guesses.

path: scripts/teletalk-alljobs-search.js
content: const fs = require('fs');
const path = require('path');
const https = require('https');
const { URL } = require('url');

const root = path.join(__dirname, '..');
const dataDir = path.join(root, 'data');
const preferencePath = path.join(dataDir, 'preference.json');

function ensureFile(file, fallback) {
  if (!fs.existsSync(file)) fs.writeFileSync(file, JSON.stringify(fallback, null, 2) + '\n');
}

function readJson(file, fallback) {
  try {
    return JSON.parse(fs.readFileSync(file, 'utf8'));
  } catch {
    return fallback;
  }
}

function requestJson(url) {
  return new Promise((resolve, reject) => {
    const req = https.request(url, { method: 'GET', headers: { 'User-Agent': 'OpenClaw/TeletalkAllJobsSkill' } }, res => {
      let body = '';
      res.on('data', chunk => body += chunk);
      res.on('end', () => {
        try { resolve(JSON.parse(body)); }
        catch { resolve({ raw: body, statusCode: res.statusCode }); }
      });
    });
    req.on('error', reject);
    req.end();
  });
}

function formatDeadline(value) {
  if (!value) return value;
  const d = new Date(value);
  if (Number.isNaN(d.getTime())) return value;
  return new Intl.DateTimeFormat('en-GB', {
    timeZone: 'Asia/Dhaka',
    dateStyle: 'medium',
    timeStyle: 'short',
    hour12: true,
  }).format(d);
}

function isOverdue(value) {
  const d = new Date(value);
  return !Number.isNaN(d.getTime()) && d.getTime() < Date.now();
}

(async () => {
  ensureFile(preferencePath, { keyboard: '', excluded: [] });
  const prefs = readJson(preferencePath, { keyboard: '', excluded: [] });
  const keyword = String(prefs.keyboard || '').trim();
  const excluded = Array.isArray(prefs.excluded) ? prefs.excluded.map(x => String(x).trim()).filter(Boolean) : [];

  if (!keyword) throw new Error('Missing preference.keyboard');

  const url = new URL('https://alljobs.teletalk.com.bd/api/v1/published-jobs/search');
  url.searchParams.set('searchKeyword', keyword);
  const res = await requestJson(url.toString());
  const jobs = Array.isArray(res?.govtJobs) ? res.govtJobs : [];

  const filtered = jobs.filter(job => {
    const title = String(job.job_title || '').toLowerCase();
    return !excluded.some(word => title.includes(word.toLowerCase())) && !isOverdue(job.deadline_date);
  }).map(job => ({
    job_primary_id: job.job_primary_id,
    job_title: job.job_title,
    job_title_bn: job.job_title_bn,
    org_name: job.org_name,
    org_name_bn: job.org_name_bn,
    vacancy: job.vacancy,
    deadline_date: formatDeadline(job.deadline_date),
    application_site_url: job.application_site_url,
  }));

  console.log(JSON.stringify(filtered, null, 2));
})().catch(err => {
  console.error(err.stack || String(err));
  process.exit(1);
});


path: data/appliedJobIds.json

path: data/preference.json
content: {
  "keyboard": "",
  "excluded": []
}

Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)