aacp-ts 1.1.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 (49) hide show
  1. package/README.md +122 -0
  2. package/Src/decoder.ts +131 -0
  3. package/Src/encoders/ruleBasedEncoder.ts +140 -0
  4. package/Src/encoders/workflows/contractEncoder.ts +68 -0
  5. package/Src/encoders/workflows/invoiceEncoder.ts +71 -0
  6. package/Src/encoders/workflows/itEncoder.ts +95 -0
  7. package/Src/encoders/workflows/payrollEncoder.ts +110 -0
  8. package/Src/index.ts +27 -0
  9. package/Src/schema.ts +107 -0
  10. package/Src/validator.ts +127 -0
  11. package/dist/decoder.d.ts +12 -0
  12. package/dist/decoder.d.ts.map +1 -0
  13. package/dist/decoder.js +124 -0
  14. package/dist/decoder.js.map +1 -0
  15. package/dist/encoders/ruleBasedEncoder.d.ts +12 -0
  16. package/dist/encoders/ruleBasedEncoder.d.ts.map +1 -0
  17. package/dist/encoders/ruleBasedEncoder.js +113 -0
  18. package/dist/encoders/ruleBasedEncoder.js.map +1 -0
  19. package/dist/encoders/workflows/contractEncoder.d.ts +13 -0
  20. package/dist/encoders/workflows/contractEncoder.d.ts.map +1 -0
  21. package/dist/encoders/workflows/contractEncoder.js +43 -0
  22. package/dist/encoders/workflows/contractEncoder.js.map +1 -0
  23. package/dist/encoders/workflows/invoiceEncoder.d.ts +13 -0
  24. package/dist/encoders/workflows/invoiceEncoder.d.ts.map +1 -0
  25. package/dist/encoders/workflows/invoiceEncoder.js +49 -0
  26. package/dist/encoders/workflows/invoiceEncoder.js.map +1 -0
  27. package/dist/encoders/workflows/itEncoder.d.ts +15 -0
  28. package/dist/encoders/workflows/itEncoder.d.ts.map +1 -0
  29. package/dist/encoders/workflows/itEncoder.js +69 -0
  30. package/dist/encoders/workflows/itEncoder.js.map +1 -0
  31. package/dist/encoders/workflows/payrollEncoder.d.ts +17 -0
  32. package/dist/encoders/workflows/payrollEncoder.d.ts.map +1 -0
  33. package/dist/encoders/workflows/payrollEncoder.js +76 -0
  34. package/dist/encoders/workflows/payrollEncoder.js.map +1 -0
  35. package/dist/index.d.ts +22 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +35 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/schema.d.ts +86 -0
  40. package/dist/schema.d.ts.map +1 -0
  41. package/dist/schema.js +25 -0
  42. package/dist/schema.js.map +1 -0
  43. package/dist/validator.d.ts +10 -0
  44. package/dist/validator.d.ts.map +1 -0
  45. package/dist/validator.js +112 -0
  46. package/dist/validator.js.map +1 -0
  47. package/package.json +47 -0
  48. package/tests/smoke.test.ts +162 -0
  49. package/tsconfig.json +29 -0
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # aacp-ts — AACP TypeScript SDK
2
+
3
+ **Agent Action Compression Protocol — TypeScript SDK**
4
+
5
+ Deterministic, zero-cost encoding of agent coordination messages.
6
+ TypeScript port of the [Python SDK](https://github.com/MackayAndrew/aacp).
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install aacp-ts
12
+ ```
13
+
14
+ ## Quick start
15
+
16
+ ```typescript
17
+ import { PayrollEncoder, AACPValidator, AACPDecoder } from "aacp-ts";
18
+
19
+ // Zero-cost rule-based encoding
20
+ const enc = new PayrollEncoder();
21
+ const pkt = enc.fetchEmployees("2026-03");
22
+ console.log(pkt.packet);
23
+ // FETCH|HR|return:HR-Agent|p:1|aacp:1.1|res:emp_salary|period:2026-03|filter:status=active|fmt:json
24
+ console.log(pkt.apiCostUsd); // 0
25
+
26
+ // Validate any packet
27
+ const validator = new AACPValidator();
28
+ const result = validator.validate(pkt.packet);
29
+ console.log(result.valid); // true
30
+ console.log(result.summary());
31
+
32
+ // Decode any packet to English
33
+ const decoder = new AACPDecoder();
34
+ const decoded = decoder.decode(pkt.packet);
35
+ console.log(decoded.english);
36
+ ```
37
+
38
+ ## Workflow encoders
39
+
40
+ ```typescript
41
+ import {
42
+ PayrollEncoder, // HR payroll — 6 hops
43
+ ITEncoder, // IT provisioning — 5 hops
44
+ InvoiceEncoder, // AP invoice processing — 3 hops
45
+ ContractEncoder, // Legal contract review — 2+ hops
46
+ } from "aacp-ts";
47
+
48
+ // Full payroll run — all 6 packets, $0.00 total
49
+ const payroll = new PayrollEncoder();
50
+ const packets = payroll.fullRun("2026-03", "2026-02");
51
+
52
+ // IT provisioning
53
+ const it = new ITEncoder();
54
+ const provision = it.fullProvision("j.smith", "Engineering", ["M365", "Slack"]);
55
+
56
+ // Invoice processing
57
+ const inv = new InvoiceEncoder();
58
+ const invoice = inv.fullProcess("Acme-Ltd", 4200, "GBP", "PO-441");
59
+
60
+ // Legal contract review
61
+ const contract = new ContractEncoder();
62
+ contract.flagClause("NDA", "Acme-Ltd", "s7", "ip_rights_restriction", "high", "signature");
63
+ ```
64
+
65
+ ## Rule-based encoder (direct)
66
+
67
+ ```typescript
68
+ import { RuleBasedEncoder } from "aacp-ts";
69
+
70
+ const enc = new RuleBasedEncoder();
71
+ const pkt = enc.encode({
72
+ task: "FETCH",
73
+ domain: "HR",
74
+ returnAgent: "HR-Agent",
75
+ res: "emp_salary",
76
+ period: "2026-03",
77
+ filterExpr: "status=active",
78
+ fmt: "json",
79
+ });
80
+ ```
81
+
82
+ ## Packet format
83
+
84
+ ```
85
+ TASK|DOM|return:AGENT|p:PRIORITY|aacp:1.1|key:value...
86
+
87
+ TASK and DOM are positional. Everything else is named key:value.
88
+ No empty positional slots.
89
+
90
+ Valid TASK: FETCH PROC FLAG RESOLVE LOG SEND BUILD MERGE CALC REPORT ACK SYNC
91
+ Valid DOM: HR FIN SALES LEGAL IT CS MKT
92
+ ```
93
+
94
+ ## Development
95
+
96
+ ```bash
97
+ npm install
98
+ npm run build
99
+ npm test
100
+ ```
101
+
102
+ ## Relationship to Python SDK
103
+
104
+ This TypeScript SDK mirrors the Python SDK exactly:
105
+ - Same packet format and AACP version (v1.1)
106
+ - Same workflow encoders with identical output
107
+ - Same validator logic and rules
108
+ - Same decoder output structure
109
+
110
+ Packets produced by the TypeScript SDK are valid inputs
111
+ to the Python SDK and vice versa.
112
+
113
+ ## Links
114
+
115
+ - Spec: https://aacp.dev
116
+ - Python SDK: https://github.com/MackayAndrew/aacp
117
+ - IETF Draft: https://datatracker.ietf.org/doc/draft-mackay-aacp/
118
+ - PyPI: https://pypi.org/project/aacp/
119
+
120
+ ## Licence
121
+
122
+ MIT
package/Src/decoder.ts ADDED
@@ -0,0 +1,131 @@
1
+ /**
2
+ * AACP v1.1 Decoder
3
+ * Expands AACP packets into human-readable English.
4
+ * Pure logic. No LLM calls.
5
+ * Note: decoded output is structural, not semantic.
6
+ * The packet is always the canonical record.
7
+ */
8
+
9
+ import { DecodedPacket } from "./schema";
10
+
11
+ const TASK_VERBS: Record<string, string> = {
12
+ FETCH: "Retrieve",
13
+ PROC: "Process",
14
+ FLAG: "Flag for review",
15
+ RESOLVE: "Resolve",
16
+ LOG: "Log to audit trail",
17
+ SEND: "Send",
18
+ BUILD: "Build or provision",
19
+ MERGE: "Merge and process",
20
+ CALC: "Calculate",
21
+ REPORT: "Generate report",
22
+ ACK: "Acknowledge",
23
+ SYNC: "Synchronise",
24
+ };
25
+
26
+ const DOMAIN_NAMES: Record<string, string> = {
27
+ HR: "Human Resources",
28
+ FIN: "Finance",
29
+ SALES: "Sales",
30
+ LEGAL: "Legal",
31
+ IT: "IT",
32
+ CS: "Customer Services",
33
+ MKT: "Marketing",
34
+ };
35
+
36
+ export class AACPDecoder {
37
+
38
+ decode(packet: string): DecodedPacket {
39
+ if (!packet || !packet.trim()) {
40
+ return {
41
+ english: "Empty packet.",
42
+ parsed: {},
43
+ isComplete: false,
44
+ caveat: "Decoded output is structural. Packet is the canonical record.",
45
+ };
46
+ }
47
+
48
+ const fields = packet.trim().split("|");
49
+ const task = fields[0]?.trim() ?? "";
50
+ const dom = fields[1]?.trim() ?? "";
51
+
52
+ const named: Record<string, string> = {};
53
+ for (const f of fields.slice(2)) {
54
+ const trimmed = f.trim();
55
+ if (!trimmed) continue;
56
+ const colonIdx = trimmed.indexOf(":");
57
+ if (colonIdx !== -1) {
58
+ const key = trimmed.slice(0, colonIdx).toLowerCase();
59
+ const val = trimmed.slice(colonIdx + 1);
60
+ named[key] = val;
61
+ }
62
+ }
63
+
64
+ const verb = TASK_VERBS[task] ?? task.toLowerCase();
65
+ const domainName = DOMAIN_NAMES[dom] ?? dom;
66
+ const returnTo = named["return"] ?? "unknown agent";
67
+ const priority = named["p"] ?? "2";
68
+ const priorityLabel = priority === "1" ? "critical priority"
69
+ : priority === "3" ? "low priority"
70
+ : "standard priority";
71
+
72
+ const parts: string[] = [];
73
+
74
+ // Core action
75
+ const res = named["res"];
76
+ if (res) {
77
+ parts.push(`${verb} ${res.replace(/_/g, " ")} from the ${domainName} domain`);
78
+ } else {
79
+ parts.push(`${verb} in the ${domainName} domain`);
80
+ }
81
+
82
+ // Time period
83
+ if (named["period"]) parts.push(`for period ${named["period"]}`);
84
+
85
+ // Filter
86
+ if (named["filter"]) parts.push(`filtered to ${named["filter"].replace(/=/g, ": ").replace(/_/g, " ")}`);
87
+
88
+ // Format
89
+ if (named["fmt"]) parts.push(`return as ${named["fmt"].toUpperCase()}`);
90
+
91
+ // Rules
92
+ if (named["rules"]) parts.push(`using rules ${named["rules"]}`);
93
+
94
+ // Validate
95
+ if (named["validate"]) parts.push(`validate against ${named["validate"].replace(/_/g, " ")}`);
96
+
97
+ // Flags
98
+ if (named["flags"]) parts.push(`flag: ${named["flags"].replace(/,/g, ", ")}`);
99
+
100
+ // Highlight
101
+ if (named["highlight"]) parts.push(`highlight: ${named["highlight"].replace(/_/g, " ")}`);
102
+
103
+ // Risk
104
+ if (named["risk"]) parts.push(`risk level: ${named["risk"]}`);
105
+
106
+ // Amount
107
+ if (named["amt"]) {
108
+ const ccy = named["ccy"] ?? "";
109
+ parts.push(`amount: ${ccy} ${named["amt"]}`.trim());
110
+ }
111
+
112
+ // Recipient
113
+ if (named["to"]) parts.push(`send to: ${named["to"].replace(/,/g, ", ")}`);
114
+
115
+ // Actor / chain
116
+ if (named["actor"]) parts.push(`initiated by ${named["actor"]}`);
117
+ if (named["chain"]) parts.push(`agent chain: ${named["chain"].replace(/,/g, " → ")}`);
118
+
119
+ // Routing
120
+ parts.push(`return result to ${returnTo} (${priorityLabel})`);
121
+
122
+ const english = parts.join(", ") + ".";
123
+
124
+ return {
125
+ english,
126
+ parsed: { task, domain: dom, ...named },
127
+ isComplete: true,
128
+ caveat: "Decoded output is structural. Packet is the canonical record.",
129
+ };
130
+ }
131
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * AACP v1.1 Rule-Based Encoder
3
+ * Deterministic, zero-cost encoding for structured input.
4
+ * Everything except TASK and DOM is a named key:value pair.
5
+ * No empty positional slots. No LLM calls.
6
+ */
7
+
8
+ import { AACP_VERSION, EncodeParams, EncodedPacket } from "../schema";
9
+ import { AACPValidator } from "../validator";
10
+
11
+ class EncodedPacketImpl implements EncodedPacket {
12
+ constructor(
13
+ public packet: string,
14
+ public domain: string,
15
+ public task: string,
16
+ public tokenEstimateEnglish: number,
17
+ public tokenEstimatePacket: number,
18
+ public compressionLoss: "none" | "minor" | "partial" | "significant",
19
+ public lossNote: string | null,
20
+ public aacpVersion: string,
21
+ public encoderType: "rule_based" | "llm" | "fallback",
22
+ public apiCostUsd: number,
23
+ ) {}
24
+
25
+ get compressionRatio(): number {
26
+ if (this.tokenEstimateEnglish === 0) return 0;
27
+ return 1 - this.tokenEstimatePacket / this.tokenEstimateEnglish;
28
+ }
29
+
30
+ get reductionPct(): string {
31
+ return `${(this.compressionRatio * 100).toFixed(1)}%`;
32
+ }
33
+
34
+ summary(): string {
35
+ return [
36
+ `PACKET [${this.domain}/${this.task}]`,
37
+ ` Encoder: ${this.encoderType} Cost: $${this.apiCostUsd.toFixed(4)}`,
38
+ ` Loss: ${this.compressionLoss}`,
39
+ "",
40
+ this.packet,
41
+ ].join("\n");
42
+ }
43
+ }
44
+
45
+ export class RuleBasedEncoder {
46
+ private validator = new AACPValidator();
47
+
48
+ encode(params: EncodeParams): EncodedPacket {
49
+ const {
50
+ task, domain, returnAgent, priority = "2",
51
+ res, period, filterExpr, fields, fmt,
52
+ src, srcPrev, rules, validate, template, dataPtr,
53
+ amt, ccy, supplier, match, terms, docType, party, clause,
54
+ issue, risk, block, flags, flagsInherit, req, highlight,
55
+ status, to, subj, att, flagMsg, tone, sentiment,
56
+ actor, chain, prog, ltv, loyalty, urgency,
57
+ } = params;
58
+
59
+ // Core: TASK and DOM positional, everything else named
60
+ const parts: string[] = [
61
+ task.toUpperCase(),
62
+ domain.toUpperCase(),
63
+ `return:${returnAgent}`,
64
+ `p:${priority}`,
65
+ `aacp:${AACP_VERSION}`,
66
+ ];
67
+
68
+ const add = (key: string, val: string | number | null | undefined) => {
69
+ if (val !== null && val !== undefined && String(val).trim() !== "") {
70
+ parts.push(`${key}:${val}`);
71
+ }
72
+ };
73
+
74
+ add("res", res);
75
+ add("period", period);
76
+ add("filter", filterExpr);
77
+ add("fields", fields?.join(","));
78
+ add("fmt", fmt);
79
+ add("src", src?.join(","));
80
+ add("src_prev", srcPrev);
81
+ add("rules", rules);
82
+ add("validate", validate);
83
+ add("tmpl", template);
84
+ add("data_ptr", dataPtr);
85
+ add("amt", amt !== undefined ? String(amt) : undefined);
86
+ add("ccy", ccy?.toUpperCase());
87
+ add("sup", supplier?.replace(/ /g, "-"));
88
+ add("match", match);
89
+ add("terms", terms);
90
+ add("type", docType?.toUpperCase());
91
+ add("party", party?.replace(/ /g, "-"));
92
+ add("clause", clause);
93
+ add("issue", issue?.replace(/ /g, "_").toLowerCase());
94
+ add("risk", risk?.toLowerCase());
95
+ add("block", block);
96
+ add("flags", flags?.join(","));
97
+ add("flags_inherit", flagsInherit?.join(","));
98
+ add("req", req?.join(","));
99
+ add("highlight", highlight);
100
+ add("status", status);
101
+ add("to", to?.join(","));
102
+ add("subj", subj?.replace(/ /g, "_"));
103
+ add("att", att);
104
+ add("flag_msg", flagMsg?.replace(/ /g, "_"));
105
+ add("sentiment", sentiment?.toLowerCase());
106
+ add("tone", tone?.toLowerCase());
107
+ add("prog", prog !== undefined ? prog.toFixed(2) : undefined);
108
+ add("actor", actor);
109
+ add("chain", chain?.join(","));
110
+ add("ltv", ltv !== undefined ? String(ltv) : undefined);
111
+ add("loyalty", loyalty);
112
+ add("urgency", urgency?.toLowerCase());
113
+
114
+ const packet = parts.join("|");
115
+
116
+ const validation = this.validator.validate(packet);
117
+ if (!validation.valid) {
118
+ throw new Error(
119
+ `Rule-based encoder produced invalid packet:\n` +
120
+ validation.errors.join("\n") + "\n" + packet
121
+ );
122
+ }
123
+
124
+ const tokenEstimatePacket = Math.max(1, Math.floor(packet.length / 4));
125
+ const tokenEstimateEnglish = 15 + parts.length * 8;
126
+
127
+ return new EncodedPacketImpl(
128
+ packet,
129
+ domain.toUpperCase(),
130
+ task.toUpperCase(),
131
+ tokenEstimateEnglish,
132
+ tokenEstimatePacket,
133
+ "none",
134
+ null,
135
+ AACP_VERSION,
136
+ "rule_based",
137
+ 0.0,
138
+ );
139
+ }
140
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * AACP v1.1 Contract Review Workflow Encoder
3
+ * Zero-cost deterministic encoding for legal contract review workflows.
4
+ */
5
+
6
+ import { RuleBasedEncoder } from "../ruleBasedEncoder";
7
+ import { EncodedPacket } from "../../schema";
8
+
9
+ export class ContractEncoder {
10
+ private enc = new RuleBasedEncoder();
11
+
12
+ flagClause(
13
+ docType: string,
14
+ party: string,
15
+ clause: string,
16
+ issue: string,
17
+ risk: "low" | "medium" | "high" | "critical",
18
+ blockAction?: string,
19
+ returnAgent = "LEG-Agent",
20
+ priority = "1",
21
+ ): EncodedPacket {
22
+ return this.enc.encode({
23
+ task: "FLAG", domain: "LEGAL",
24
+ docType, party, clause, issue, risk,
25
+ block: blockAction,
26
+ returnAgent, priority,
27
+ });
28
+ }
29
+
30
+ reviewContract(
31
+ docType: string,
32
+ party: string,
33
+ rules: string,
34
+ returnAgent = "LEG-Agent",
35
+ priority = "1",
36
+ ): EncodedPacket {
37
+ return this.enc.encode({
38
+ task: "FLAG", domain: "LEGAL",
39
+ docType, party, rules,
40
+ returnAgent, priority,
41
+ });
42
+ }
43
+
44
+ logReview(
45
+ docType: string,
46
+ party: string,
47
+ status: string,
48
+ returnAgent = "AUD-Agent",
49
+ priority = "3",
50
+ ): EncodedPacket {
51
+ return this.enc.encode({
52
+ task: "LOG", domain: "LEGAL",
53
+ docType, party, status,
54
+ returnAgent, priority,
55
+ });
56
+ }
57
+
58
+ fullReview(
59
+ docType: string,
60
+ party: string,
61
+ rules: string,
62
+ ): EncodedPacket[] {
63
+ return [
64
+ this.reviewContract(docType, party, rules),
65
+ this.logReview(docType, party, "under_review"),
66
+ ];
67
+ }
68
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * AACP v1.1 Invoice Processing Workflow Encoder
3
+ * Zero-cost deterministic encoding for AP invoice workflows.
4
+ */
5
+
6
+ import { RuleBasedEncoder } from "../ruleBasedEncoder";
7
+ import { EncodedPacket } from "../../schema";
8
+
9
+ export class InvoiceEncoder {
10
+ private enc = new RuleBasedEncoder();
11
+
12
+ processInvoice(
13
+ supplier: string,
14
+ amount: number,
15
+ currency: string,
16
+ poNumber: string,
17
+ terms = "net30",
18
+ returnAgent = "FIN-Agent",
19
+ priority = "2",
20
+ ): EncodedPacket {
21
+ return this.enc.encode({
22
+ task: "PROC", domain: "FIN",
23
+ res: "invoice",
24
+ supplier, amt: amount, ccy: currency,
25
+ match: poNumber, terms,
26
+ returnAgent, priority,
27
+ });
28
+ }
29
+
30
+ approvePayment(
31
+ poNumber: string,
32
+ returnAgent = "FIN-Agent",
33
+ priority = "1",
34
+ ): EncodedPacket {
35
+ return this.enc.encode({
36
+ task: "PROC", domain: "FIN",
37
+ res: "payment",
38
+ match: poNumber,
39
+ req: ["approve"],
40
+ returnAgent, priority,
41
+ });
42
+ }
43
+
44
+ logInvoice(
45
+ poNumber: string,
46
+ status = "approved",
47
+ returnAgent = "AUD-Agent",
48
+ priority = "3",
49
+ ): EncodedPacket {
50
+ return this.enc.encode({
51
+ task: "LOG", domain: "FIN",
52
+ res: "invoice",
53
+ match: poNumber,
54
+ status,
55
+ returnAgent, priority,
56
+ });
57
+ }
58
+
59
+ fullProcess(
60
+ supplier: string,
61
+ amount: number,
62
+ currency: string,
63
+ poNumber: string,
64
+ ): EncodedPacket[] {
65
+ return [
66
+ this.processInvoice(supplier, amount, currency, poNumber),
67
+ this.approvePayment(poNumber),
68
+ this.logInvoice(poNumber),
69
+ ];
70
+ }
71
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * AACP v1.1 IT Provisioning Workflow Encoder
3
+ * Zero-cost deterministic encoding for IT provisioning workflows.
4
+ */
5
+
6
+ import { RuleBasedEncoder } from "../ruleBasedEncoder";
7
+ import { EncodedPacket } from "../../schema";
8
+
9
+ export class ITEncoder {
10
+ private enc = new RuleBasedEncoder();
11
+
12
+ createAccount(
13
+ username: string,
14
+ dept: string,
15
+ returnAgent = "IT-Agent",
16
+ priority = "1",
17
+ ): EncodedPacket {
18
+ return this.enc.encode({
19
+ task: "BUILD", domain: "IT",
20
+ res: "ad_account",
21
+ filterExpr: `usr=${username}`,
22
+ fields: ["email", "dept", "grp", "pwd_reset"],
23
+ returnAgent, priority,
24
+ });
25
+ }
26
+
27
+ assignLicences(
28
+ username: string,
29
+ licences: string[],
30
+ returnAgent = "IT-Agent",
31
+ priority = "1",
32
+ ): EncodedPacket {
33
+ return this.enc.encode({
34
+ task: "PROC", domain: "IT",
35
+ res: "licences",
36
+ filterExpr: `usr=${username}`,
37
+ req: licences,
38
+ returnAgent, priority,
39
+ });
40
+ }
41
+
42
+ configureAccess(
43
+ username: string,
44
+ systems: string[],
45
+ returnAgent = "IT-Agent",
46
+ priority = "1",
47
+ ): EncodedPacket {
48
+ return this.enc.encode({
49
+ task: "BUILD", domain: "IT",
50
+ res: "access_profile",
51
+ filterExpr: `usr=${username}`,
52
+ req: systems,
53
+ returnAgent, priority,
54
+ });
55
+ }
56
+
57
+ sendWelcome(
58
+ username: string,
59
+ returnAgent = "IT-Agent",
60
+ priority = "2",
61
+ ): EncodedPacket {
62
+ return this.enc.encode({
63
+ task: "SEND", domain: "IT",
64
+ to: [username],
65
+ subj: `welcome_${username}_onboarding`,
66
+ flagMsg: "onboarding_complete",
67
+ returnAgent, priority,
68
+ });
69
+ }
70
+
71
+ logProvisioning(
72
+ username: string,
73
+ actor = "IT-Agent",
74
+ returnAgent = "AUD-Agent",
75
+ priority = "2",
76
+ ): EncodedPacket {
77
+ return this.enc.encode({
78
+ task: "LOG", domain: "IT",
79
+ actor,
80
+ status: "provisioned",
81
+ filterExpr: `usr=${username}`,
82
+ returnAgent, priority,
83
+ });
84
+ }
85
+
86
+ fullProvision(username: string, dept: string, licences: string[]): EncodedPacket[] {
87
+ return [
88
+ this.createAccount(username, dept),
89
+ this.assignLicences(username, licences),
90
+ this.configureAccess(username, ["email", "vpn", "sharepoint"]),
91
+ this.sendWelcome(username),
92
+ this.logProvisioning(username),
93
+ ];
94
+ }
95
+ }