tokrepo 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/tokrepo.js +55 -9
  2. package/package.json +1 -1
package/bin/tokrepo.js CHANGED
@@ -25,7 +25,7 @@ const CONFIG_DIR = path.join(os.homedir(), '.tokrepo');
25
25
  const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
26
26
  const PROJECT_CONFIG = '.tokrepo.json';
27
27
  const DEFAULT_API = 'https://api.tokrepo.com';
28
- const CLI_VERSION = '3.8.0';
28
+ const CLI_VERSION = '3.9.0';
29
29
  const VERSION_CHECK_FILE = path.join(os.homedir(), '.tokrepo', '.version-check');
30
30
  const CODEX_DIR = path.join(os.homedir(), '.codex');
31
31
  const CODEX_SKILLS_DIR = path.join(CODEX_DIR, 'skills');
@@ -999,17 +999,28 @@ async function cmdSearch() {
999
999
  const apiBase = config?.api || DEFAULT_API;
1000
1000
 
1001
1001
  try {
1002
- const encoded = encodeURIComponent(query);
1003
1002
  const pageSize = Number(args.flags.pageSize || (args.flags.all ? 200 : 20)) || 20;
1004
1003
  const sortBy = args.flags.sortBy || 'views';
1005
1004
  let page = Number(args.flags.page || 1) || 1;
1006
- let data = await apiRequest('GET', `/api/v1/tokenboard/workflows/list?keyword=${encoded}&page=${page}&page_size=${pageSize}&sort_by=${encodeURIComponent(sortBy)}`, null, config?.token, apiBase);
1005
+ const buildSearchPath = (pageNo) => {
1006
+ const params = new URLSearchParams({
1007
+ keyword: query,
1008
+ page: String(pageNo),
1009
+ page_size: String(pageSize),
1010
+ sort_by: sortBy,
1011
+ });
1012
+ if (args.flags.target) params.set('target', args.flags.target);
1013
+ if (args.flags.kind || args.flags.assetKind) params.set('kind', args.flags.kind || args.flags.assetKind);
1014
+ if (args.flags.policy) params.set('policy', args.flags.policy);
1015
+ return `/api/v1/tokenboard/workflows/list?${params.toString()}`;
1016
+ };
1017
+ let data = await apiRequest('GET', buildSearchPath(page), null, config?.token, apiBase);
1007
1018
 
1008
1019
  if (args.flags.all) {
1009
1020
  const list = [...(data.list || [])];
1010
1021
  while (list.length < (data.total || 0)) {
1011
1022
  page++;
1012
- const next = await apiRequest('GET', `/api/v1/tokenboard/workflows/list?keyword=${encoded}&page=${page}&page_size=${pageSize}&sort_by=${encodeURIComponent(sortBy)}`, null, config?.token, apiBase);
1023
+ const next = await apiRequest('GET', buildSearchPath(page), null, config?.token, apiBase);
1013
1024
  const items = next.list || [];
1014
1025
  if (items.length === 0) break;
1015
1026
  list.push(...items);
@@ -1066,9 +1077,12 @@ async function cmdSearch() {
1066
1077
  log(` ${C.dim}${String(i + 1).padStart(2)}.${C.reset} ${C.bold}${wf.title}${C.reset}`);
1067
1078
  if (desc) log(` ${desc}`);
1068
1079
  if (tags) log(` ${C.cyan}${tags}${C.reset} ${C.dim}★${votes} 👁${views}${C.reset}`);
1069
- if (wf.compatibility?.codex) {
1070
- const c = wf.compatibility.codex;
1071
- log(` ${C.dim}codex: ${c.status} · policy=${c.policyDecision.decision} · kind=${c.assetKind || 'unknown'}${C.reset}`);
1080
+ const fit = wf.agent_fit || wf.agentFit || wf.compatibility?.codex;
1081
+ if (fit) {
1082
+ const policy = fit.policy || fit.policyDecision?.decision || 'unknown';
1083
+ const kind = fit.asset_kind || fit.assetKind || 'unknown';
1084
+ const score = fit.score !== undefined ? ` · score=${fit.score}` : '';
1085
+ log(` ${C.dim}codex: ${fit.status || 'unknown'} · policy=${policy} · kind=${kind}${score}${C.reset}`);
1072
1086
  }
1073
1087
  log(` ${C.dim}tokrepo install ${wf.uuid}${C.reset}`);
1074
1088
  log('');
@@ -1756,6 +1770,22 @@ function publicInstallPlan(plan) {
1756
1770
  }
1757
1771
 
1758
1772
  function workflowCodexCompatibility(workflow) {
1773
+ if (workflow?.agent_fit || workflow?.agentFit) {
1774
+ const fit = workflow.agent_fit || workflow.agentFit;
1775
+ return {
1776
+ targetTool: fit.target || 'codex',
1777
+ status: fit.status || 'unknown',
1778
+ score: fit.score ?? 50,
1779
+ assetKind: fit.asset_kind || fit.assetKind || workflowAssetKind(workflow),
1780
+ targetTools: workflowTargetTools(workflow),
1781
+ installMode: fit.install_mode || fit.installMode || 'single',
1782
+ policyDecision: {
1783
+ decision: fit.policy || fit.policyDecision?.decision || 'allow',
1784
+ requiresConfirmation: ['confirm'].includes(fit.policy || ''),
1785
+ reasons: fit.why || fit.reasons || [],
1786
+ },
1787
+ };
1788
+ }
1759
1789
  const metadata = workflowAgentMetadata(workflow);
1760
1790
  const assetKind = workflowAssetKind(workflow);
1761
1791
  const targetTools = workflowTargetTools(workflow);
@@ -1827,10 +1857,20 @@ function workflowMatchesAgentFilters(workflow, flags = {}) {
1827
1857
 
1828
1858
  function enrichWorkflowForAgent(workflow) {
1829
1859
  const compatibility = workflowCodexCompatibility(workflow);
1860
+ const agentFit = workflow.agent_fit || workflow.agentFit || {
1861
+ target: 'codex',
1862
+ score: compatibility.score,
1863
+ status: compatibility.status,
1864
+ policy: compatibility.policyDecision.decision,
1865
+ why: compatibility.policyDecision.reasons,
1866
+ asset_kind: compatibility.assetKind,
1867
+ install_mode: compatibility.installMode,
1868
+ };
1830
1869
  return {
1831
1870
  ...workflow,
1832
1871
  assetKind: compatibility.assetKind,
1833
1872
  targetTools: compatibility.targetTools,
1873
+ agent_fit: agentFit,
1834
1874
  compatibility: {
1835
1875
  codex: compatibility,
1836
1876
  },
@@ -3020,9 +3060,15 @@ async function cmdEvalAgent() {
3020
3060
  await runScenario('search_filters_codex_allow_skill', async () => {
3021
3061
  const data = runSelfCliJson(['search', query, '--target', 'codex', '--kind', 'skill', '--policy', 'allow', '--json', '--page-size', '10']);
3022
3062
  if (!data.count || !Array.isArray(data.list)) throw new Error('filtered search returned no list');
3023
- const bad = data.list.find(item => item.policyDecision?.decision && item.policyDecision.decision !== 'allow');
3063
+ const bad = data.list.find(item => {
3064
+ const policy = item.agent_fit?.policy || item.policyDecision?.decision;
3065
+ return policy && policy !== 'allow';
3066
+ });
3024
3067
  if (bad) throw new Error(`search returned non-allow asset ${bad.uuid}`);
3025
- return { count: data.count, firstUuid: data.list[0]?.uuid, firstTitle: data.list[0]?.title };
3068
+ const firstFit = data.list[0]?.agent_fit || data.list[0]?.agentFit;
3069
+ if (!firstFit?.score && firstFit?.score !== 0) throw new Error('search result missing agent_fit.score');
3070
+ if (firstFit.policy !== 'allow') throw new Error(`first result policy is ${firstFit.policy}`);
3071
+ return { count: data.count, firstUuid: data.list[0]?.uuid, firstTitle: data.list[0]?.title, firstAgentFitScore: firstFit.score };
3026
3072
  });
3027
3073
 
3028
3074
  await runScenario('install_plan_contract', async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokrepo",
3
- "version": "3.8.0",
3
+ "version": "3.9.0",
4
4
  "description": "AI assets for humans and agents — search, install, push. Like GitHub, for AI experience.",
5
5
  "bin": {
6
6
  "tokrepo": "bin/tokrepo.js"