@wanasapps/deluge-core 1.2.0 → 1.3.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.
- package/README.md +17 -0
- package/assets/DELUGE_SKILL.md +5 -57
- package/assets/deluge-reference.json +2647 -2647
- package/package.json +2 -2
- package/scripts/check-cores-published.js +63 -0
- package/scripts/gen-skill.js +13 -11
- package/src/format/signature.js +70 -70
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wanasapps/deluge-core",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Deluge language tooling for every Zoho product: formatter, source transforms, TextMate grammar, snippets, an editor-agnostic linter, and AI-agent skills
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Deluge language tooling for every Zoho product: formatter, source transforms, TextMate grammar, snippets, an editor-agnostic linter, and AI-agent skills — a guide with runtime traps verified on a live org, plus a complete reference of every statement, data type, built-in function and integration task generated from Zoho's Deluge documentation. No I/O, no HTTP, no editor dependency.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"files": [
|
|
7
7
|
"src",
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Refuse to publish before the @wanasapps packages this one depends on.
|
|
4
|
+
*
|
|
5
|
+
* These five packages are independent repos, not a workspace. Publishing a
|
|
6
|
+
* consumer before its cores yields a package npm cannot install — it has
|
|
7
|
+
* happened before (zone 0.4.3). CI runs this before `npm ci`, so the failure
|
|
8
|
+
* names the missing package instead of surfacing as a bare ETARGET.
|
|
9
|
+
*/
|
|
10
|
+
'use strict';
|
|
11
|
+
const cp = require('child_process');
|
|
12
|
+
const pj = require('../package.json');
|
|
13
|
+
|
|
14
|
+
const deps = { ...(pj.dependencies || {}), ...(pj.peerDependencies || {}) };
|
|
15
|
+
const wanas = Object.entries(deps).filter(([n]) => n.startsWith('@wanasapps'));
|
|
16
|
+
|
|
17
|
+
if (!wanas.length) {
|
|
18
|
+
console.log('no @wanasapps dependencies — nothing to check');
|
|
19
|
+
process.exit(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// A lockfile that records a local link resolves on the dev machine and
|
|
23
|
+
// nowhere else: `npm ci` creates the link, exits 0, and the module is
|
|
24
|
+
// missing at runtime. Caught zoho-api 1.1.1 in CI.
|
|
25
|
+
try {
|
|
26
|
+
const lock = require('../package-lock.json');
|
|
27
|
+
const linked = Object.entries(lock.packages || {})
|
|
28
|
+
.filter(([, v]) => v && v.link)
|
|
29
|
+
.map(([k]) => k.replace('node_modules/', ''));
|
|
30
|
+
if (linked.length) {
|
|
31
|
+
console.error(` LINKED ${linked.join(', ')} recorded as a local link in package-lock.json`);
|
|
32
|
+
console.error(' Regenerate it against the registry: npm install --package-lock-only');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
} catch { /* no lockfile is fine */ }
|
|
36
|
+
|
|
37
|
+
let missing = 0;
|
|
38
|
+
for (const [name, range] of wanas) {
|
|
39
|
+
let found = '';
|
|
40
|
+
try {
|
|
41
|
+
// --json so a range matching several versions returns an array, rather
|
|
42
|
+
// than npm's "<name>@<ver> '<ver>'" lines, which are awkward to parse.
|
|
43
|
+
const raw = cp.execSync(`npm view ${name}@"${range}" version --json`, {
|
|
44
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore']
|
|
45
|
+
}).trim();
|
|
46
|
+
const parsed = raw ? JSON.parse(raw) : null;
|
|
47
|
+
found = Array.isArray(parsed) ? parsed[parsed.length - 1] : (parsed || '');
|
|
48
|
+
} catch { /* not published, or the range matches nothing */ }
|
|
49
|
+
|
|
50
|
+
if (found) {
|
|
51
|
+
console.log(` ok ${name}@${range} -> ${found}`);
|
|
52
|
+
} else {
|
|
53
|
+
console.error(` MISSING ${name}@${range} does not resolve on npm`);
|
|
54
|
+
missing++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (missing) {
|
|
59
|
+
console.error('\nPublish bottom-up:');
|
|
60
|
+
console.error(' deluge-core -> zoho-auth -> zoho-api -> zcrm-core -> wanas-zone-cli');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
console.log('all @wanasapps dependencies resolve on npm');
|
package/scripts/gen-skill.js
CHANGED
|
@@ -55,10 +55,13 @@ const prodOrder = ['crm', ...[...taskByProd.keys()].filter((k) => k !== 'crm').s
|
|
|
55
55
|
// ---------------------------------------------------------------------------
|
|
56
56
|
// DELUGE_SKILL.md — guide + complete name index
|
|
57
57
|
// ---------------------------------------------------------------------------
|
|
58
|
+
const fnCount = [...fnByCat.values()].reduce((n, v) => n + v.length, 0);
|
|
59
|
+
const taskCount = [...taskByProd.values()].reduce((n, v) => n + v.length, 0);
|
|
60
|
+
|
|
58
61
|
const skill = [];
|
|
59
62
|
skill.push(guide.trimEnd(), '', '---', '');
|
|
60
63
|
skill.push('# Part 2 — Everything that exists (names only)', '');
|
|
61
|
-
skill.push(`
|
|
64
|
+
skill.push(`What exists in Deluge, generated from ${ref.source}. Statements and data types are listed in full below because they are few. The ${fnCount} built-in functions and ${taskCount} integration tasks are summarised by category — **every one of them is named, with its exact syntax, parameters and return type, in the companion reference**: read \`references/REFERENCE.md\` in this skill folder, or run \`zone llm deluge-reference\`. If a name is not there, it does not exist in Deluge — do not invent one.`, '');
|
|
62
65
|
|
|
63
66
|
skill.push('## Statements', '');
|
|
64
67
|
skill.push((ref.statements || []).map((s) => `\`${s.name}\``).concat(['`invokeurl`', '`info`', '`return`']).join(' · '), '');
|
|
@@ -66,17 +69,16 @@ skill.push((ref.statements || []).map((s) => `\`${s.name}\``).concat(['`invokeur
|
|
|
66
69
|
skill.push('## Data types', '');
|
|
67
70
|
skill.push((ref.datatypes || []).map((d) => `\`${d.name}\``).join(' · '), '');
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
// Categories and counts, not 337 names. Every one of those names already
|
|
73
|
+
// appears in DELUGE_REFERENCE.md WITH its syntax, so listing them here bought
|
|
74
|
+
// nothing and cost ~1,800 tokens on every trigger — pushing the skill body over
|
|
75
|
+
// the Agent Skills spec's 5,000-token recommendation. The agent is told where
|
|
76
|
+
// to look instead, which preserves the "do not invent a name" guarantee.
|
|
77
|
+
skill.push('## Built-in functions — ' + fnCount + ' across ' + catOrder.length + ' categories', '');
|
|
78
|
+
skill.push(catOrder.map((cat) => `**${cat}** (${fnByCat.get(cat).length})`).join(' · '), '');
|
|
74
79
|
|
|
75
|
-
skill.push('## Integration tasks', '');
|
|
76
|
-
|
|
77
|
-
const names = taskByProd.get(prod).slice().sort(byName).map((t) => `\`${t.name}\``);
|
|
78
|
-
skill.push(`**${LABEL[prod] || prod}** (${names.length}): ${names.join(', ')}`, '');
|
|
79
|
-
}
|
|
80
|
+
skill.push('## Integration tasks — ' + taskCount + ' across ' + prodOrder.length + ' products', '');
|
|
81
|
+
skill.push(prodOrder.map((prod) => `**${LABEL[prod] || prod}** (${taskByProd.get(prod).length})`).join(' · '), '');
|
|
80
82
|
|
|
81
83
|
skill.push('## System variables', '');
|
|
82
84
|
skill.push('`zoho.currentdate`, `zoho.currenttime`, `zoho.loginuser`, `zoho.loginuser.name` (Creator), `zoho.loginuserid`, `zoho.adminuser`, `zoho.adminuserid`, `zoho.appname` (Creator), `zoho.appuri` (Creator), `zoho.ipaddress`, `zoho.device.type` (Creator).', '');
|
package/src/format/signature.js
CHANGED
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal parser for the *signature line* of a Deluge function script.
|
|
3
|
-
*
|
|
4
|
-
* Zoho stores a function's code with its signature on the first meaningful
|
|
5
|
-
* line, e.g.:
|
|
6
|
-
*
|
|
7
|
-
* string standalone.Get_Assistants()
|
|
8
|
-
* void automation.k_test(String Data)
|
|
9
|
-
*
|
|
10
|
-
* We only need the signature to learn the function's namespace + api name (to
|
|
11
|
-
* build the test URL and enforce the standalone-only rule) and its declared
|
|
12
|
-
* arguments (to prompt for values). The full script is still submitted verbatim
|
|
13
|
-
* to Zoho — this parser never rewrites the code.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Parse the signature of a Deluge script.
|
|
18
|
-
* @param {string} scriptText - The full Deluge source.
|
|
19
|
-
* @returns {{returnType: string|null, namespace: string|null, apiName: string|null, args: Array<{type:string,name:string}>}}
|
|
20
|
-
*/
|
|
21
|
-
function parseSignature(scriptText) {
|
|
22
|
-
const result = { returnType: null, namespace: null, apiName: null, args: [] };
|
|
23
|
-
if (!scriptText || typeof scriptText !== 'string') return result;
|
|
24
|
-
|
|
25
|
-
// Find the first non-comment, non-blank line — that's the signature.
|
|
26
|
-
let sigLine = null;
|
|
27
|
-
let inBlockComment = false;
|
|
28
|
-
for (const raw of scriptText.split('\n')) {
|
|
29
|
-
let line = raw.trim();
|
|
30
|
-
if (!line) continue;
|
|
31
|
-
|
|
32
|
-
if (inBlockComment) {
|
|
33
|
-
const end = line.indexOf('*/');
|
|
34
|
-
if (end === -1) continue;
|
|
35
|
-
line = line.slice(end + 2).trim();
|
|
36
|
-
inBlockComment = false;
|
|
37
|
-
if (!line) continue;
|
|
38
|
-
}
|
|
39
|
-
if (line.startsWith('//')) continue;
|
|
40
|
-
if (line.startsWith('/*')) {
|
|
41
|
-
const end = line.indexOf('*/');
|
|
42
|
-
if (end === -1) { inBlockComment = true; continue; }
|
|
43
|
-
line = line.slice(end + 2).trim();
|
|
44
|
-
if (!line) continue;
|
|
45
|
-
}
|
|
46
|
-
sigLine = line;
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
if (!sigLine) return result;
|
|
50
|
-
|
|
51
|
-
// <returnType> <namespace>.<apiName>(<args>)
|
|
52
|
-
const m = sigLine.match(/^(\w+)\s+([A-Za-z0-9_]+)\.([A-Za-z0-9_]+)\s*\(([^)]*)\)/);
|
|
53
|
-
if (!m) return result;
|
|
54
|
-
|
|
55
|
-
result.returnType = m[1];
|
|
56
|
-
result.namespace = m[2];
|
|
57
|
-
result.apiName = m[3];
|
|
58
|
-
|
|
59
|
-
const argsRaw = m[4].trim();
|
|
60
|
-
if (argsRaw) {
|
|
61
|
-
for (const part of argsRaw.split(',')) {
|
|
62
|
-
// each param is "<type> <name>" (e.g. "String Data", "int count")
|
|
63
|
-
const am = part.trim().match(/^(\S+)\s+([A-Za-z0-9_]+)$/);
|
|
64
|
-
if (am) result.args.push({ type: am[1], name: am[2] });
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
module.exports = { parseSignature };
|
|
1
|
+
/**
|
|
2
|
+
* Minimal parser for the *signature line* of a Deluge function script.
|
|
3
|
+
*
|
|
4
|
+
* Zoho stores a function's code with its signature on the first meaningful
|
|
5
|
+
* line, e.g.:
|
|
6
|
+
*
|
|
7
|
+
* string standalone.Get_Assistants()
|
|
8
|
+
* void automation.k_test(String Data)
|
|
9
|
+
*
|
|
10
|
+
* We only need the signature to learn the function's namespace + api name (to
|
|
11
|
+
* build the test URL and enforce the standalone-only rule) and its declared
|
|
12
|
+
* arguments (to prompt for values). The full script is still submitted verbatim
|
|
13
|
+
* to Zoho — this parser never rewrites the code.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Parse the signature of a Deluge script.
|
|
18
|
+
* @param {string} scriptText - The full Deluge source.
|
|
19
|
+
* @returns {{returnType: string|null, namespace: string|null, apiName: string|null, args: Array<{type:string,name:string}>}}
|
|
20
|
+
*/
|
|
21
|
+
function parseSignature(scriptText) {
|
|
22
|
+
const result = { returnType: null, namespace: null, apiName: null, args: [] };
|
|
23
|
+
if (!scriptText || typeof scriptText !== 'string') return result;
|
|
24
|
+
|
|
25
|
+
// Find the first non-comment, non-blank line — that's the signature.
|
|
26
|
+
let sigLine = null;
|
|
27
|
+
let inBlockComment = false;
|
|
28
|
+
for (const raw of scriptText.split('\n')) {
|
|
29
|
+
let line = raw.trim();
|
|
30
|
+
if (!line) continue;
|
|
31
|
+
|
|
32
|
+
if (inBlockComment) {
|
|
33
|
+
const end = line.indexOf('*/');
|
|
34
|
+
if (end === -1) continue;
|
|
35
|
+
line = line.slice(end + 2).trim();
|
|
36
|
+
inBlockComment = false;
|
|
37
|
+
if (!line) continue;
|
|
38
|
+
}
|
|
39
|
+
if (line.startsWith('//')) continue;
|
|
40
|
+
if (line.startsWith('/*')) {
|
|
41
|
+
const end = line.indexOf('*/');
|
|
42
|
+
if (end === -1) { inBlockComment = true; continue; }
|
|
43
|
+
line = line.slice(end + 2).trim();
|
|
44
|
+
if (!line) continue;
|
|
45
|
+
}
|
|
46
|
+
sigLine = line;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
if (!sigLine) return result;
|
|
50
|
+
|
|
51
|
+
// <returnType> <namespace>.<apiName>(<args>)
|
|
52
|
+
const m = sigLine.match(/^(\w+)\s+([A-Za-z0-9_]+)\.([A-Za-z0-9_]+)\s*\(([^)]*)\)/);
|
|
53
|
+
if (!m) return result;
|
|
54
|
+
|
|
55
|
+
result.returnType = m[1];
|
|
56
|
+
result.namespace = m[2];
|
|
57
|
+
result.apiName = m[3];
|
|
58
|
+
|
|
59
|
+
const argsRaw = m[4].trim();
|
|
60
|
+
if (argsRaw) {
|
|
61
|
+
for (const part of argsRaw.split(',')) {
|
|
62
|
+
// each param is "<type> <name>" (e.g. "String Data", "int count")
|
|
63
|
+
const am = part.trim().match(/^(\S+)\s+([A-Za-z0-9_]+)$/);
|
|
64
|
+
if (am) result.args.push({ type: am[1], name: am[2] });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { parseSignature };
|