openclaw-telegram-manager 1.0.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 (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -0
  3. package/dist/commands/archive.d.ts +4 -0
  4. package/dist/commands/archive.d.ts.map +1 -0
  5. package/dist/commands/archive.js +71 -0
  6. package/dist/commands/archive.js.map +1 -0
  7. package/dist/commands/doctor-all.d.ts +3 -0
  8. package/dist/commands/doctor-all.d.ts.map +1 -0
  9. package/dist/commands/doctor-all.js +193 -0
  10. package/dist/commands/doctor-all.js.map +1 -0
  11. package/dist/commands/doctor.d.ts +3 -0
  12. package/dist/commands/doctor.d.ts.map +1 -0
  13. package/dist/commands/doctor.js +74 -0
  14. package/dist/commands/doctor.js.map +1 -0
  15. package/dist/commands/help.d.ts +4 -0
  16. package/dist/commands/help.d.ts.map +1 -0
  17. package/dist/commands/help.js +8 -0
  18. package/dist/commands/help.js.map +1 -0
  19. package/dist/commands/init.d.ts +17 -0
  20. package/dist/commands/init.d.ts.map +1 -0
  21. package/dist/commands/init.js +304 -0
  22. package/dist/commands/init.js.map +1 -0
  23. package/dist/commands/list.d.ts +3 -0
  24. package/dist/commands/list.d.ts.map +1 -0
  25. package/dist/commands/list.js +22 -0
  26. package/dist/commands/list.js.map +1 -0
  27. package/dist/commands/rename.d.ts +3 -0
  28. package/dist/commands/rename.d.ts.map +1 -0
  29. package/dist/commands/rename.js +115 -0
  30. package/dist/commands/rename.js.map +1 -0
  31. package/dist/commands/snooze.d.ts +3 -0
  32. package/dist/commands/snooze.d.ts.map +1 -0
  33. package/dist/commands/snooze.js +52 -0
  34. package/dist/commands/snooze.js.map +1 -0
  35. package/dist/commands/status.d.ts +3 -0
  36. package/dist/commands/status.d.ts.map +1 -0
  37. package/dist/commands/status.js +48 -0
  38. package/dist/commands/status.js.map +1 -0
  39. package/dist/commands/sync.d.ts +3 -0
  40. package/dist/commands/sync.d.ts.map +1 -0
  41. package/dist/commands/sync.js +38 -0
  42. package/dist/commands/sync.js.map +1 -0
  43. package/dist/commands/upgrade.d.ts +3 -0
  44. package/dist/commands/upgrade.d.ts.map +1 -0
  45. package/dist/commands/upgrade.js +52 -0
  46. package/dist/commands/upgrade.js.map +1 -0
  47. package/dist/index.d.ts +25 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +30 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/lib/audit.d.ts +12 -0
  52. package/dist/lib/audit.d.ts.map +1 -0
  53. package/dist/lib/audit.js +35 -0
  54. package/dist/lib/audit.js.map +1 -0
  55. package/dist/lib/auth.d.ts +26 -0
  56. package/dist/lib/auth.d.ts.map +1 -0
  57. package/dist/lib/auth.js +73 -0
  58. package/dist/lib/auth.js.map +1 -0
  59. package/dist/lib/capsule.d.ts +27 -0
  60. package/dist/lib/capsule.d.ts.map +1 -0
  61. package/dist/lib/capsule.js +130 -0
  62. package/dist/lib/capsule.js.map +1 -0
  63. package/dist/lib/config-restart.d.ts +23 -0
  64. package/dist/lib/config-restart.d.ts.map +1 -0
  65. package/dist/lib/config-restart.js +129 -0
  66. package/dist/lib/config-restart.js.map +1 -0
  67. package/dist/lib/doctor-checks.d.ts +50 -0
  68. package/dist/lib/doctor-checks.d.ts.map +1 -0
  69. package/dist/lib/doctor-checks.js +421 -0
  70. package/dist/lib/doctor-checks.js.map +1 -0
  71. package/dist/lib/include-generator.d.ts +35 -0
  72. package/dist/lib/include-generator.d.ts.map +1 -0
  73. package/dist/lib/include-generator.js +140 -0
  74. package/dist/lib/include-generator.js.map +1 -0
  75. package/dist/lib/registry.d.ts +27 -0
  76. package/dist/lib/registry.d.ts.map +1 -0
  77. package/dist/lib/registry.js +154 -0
  78. package/dist/lib/registry.js.map +1 -0
  79. package/dist/lib/security.d.ts +57 -0
  80. package/dist/lib/security.d.ts.map +1 -0
  81. package/dist/lib/security.js +133 -0
  82. package/dist/lib/security.js.map +1 -0
  83. package/dist/lib/telegram.d.ts +55 -0
  84. package/dist/lib/telegram.d.ts.map +1 -0
  85. package/dist/lib/telegram.js +254 -0
  86. package/dist/lib/telegram.js.map +1 -0
  87. package/dist/lib/types.d.ts +120 -0
  88. package/dist/lib/types.d.ts.map +1 -0
  89. package/dist/lib/types.js +85 -0
  90. package/dist/lib/types.js.map +1 -0
  91. package/dist/setup.d.ts +3 -0
  92. package/dist/setup.d.ts.map +1 -0
  93. package/dist/setup.js +333 -0
  94. package/dist/setup.js.map +1 -0
  95. package/dist/tool.d.ts +15 -0
  96. package/dist/tool.d.ts.map +1 -0
  97. package/dist/tool.js +201 -0
  98. package/dist/tool.js.map +1 -0
  99. package/openclaw.plugin.json +9 -0
  100. package/package.json +48 -0
  101. package/skills/topic/SKILL.md +35 -0
  102. package/src/commands/archive.ts +89 -0
  103. package/src/commands/doctor-all.ts +243 -0
  104. package/src/commands/doctor.ts +100 -0
  105. package/src/commands/help.ts +11 -0
  106. package/src/commands/init.ts +376 -0
  107. package/src/commands/list.ts +28 -0
  108. package/src/commands/rename.ts +140 -0
  109. package/src/commands/snooze.ts +69 -0
  110. package/src/commands/status.ts +59 -0
  111. package/src/commands/sync.ts +46 -0
  112. package/src/commands/upgrade.ts +64 -0
  113. package/src/index.ts +54 -0
  114. package/src/lib/audit.ts +44 -0
  115. package/src/lib/auth.ts +96 -0
  116. package/src/lib/capsule.ts +206 -0
  117. package/src/lib/config-restart.ts +167 -0
  118. package/src/lib/doctor-checks.ts +639 -0
  119. package/src/lib/include-generator.ts +174 -0
  120. package/src/lib/registry.ts +197 -0
  121. package/src/lib/security.ts +174 -0
  122. package/src/lib/telegram.ts +311 -0
  123. package/src/lib/types.ts +172 -0
  124. package/src/setup.ts +402 -0
  125. package/src/templates/base/COMMANDS.md +3 -0
  126. package/src/templates/base/CRON.md +3 -0
  127. package/src/templates/base/LINKS.md +3 -0
  128. package/src/templates/base/NOTES.md +3 -0
  129. package/src/templates/base/README.md +3 -0
  130. package/src/templates/base/STATUS.md +13 -0
  131. package/src/templates/base/TODO.md +11 -0
  132. package/src/templates/overlays/coding/ARCHITECTURE.md +3 -0
  133. package/src/templates/overlays/coding/DEPLOY.md +3 -0
  134. package/src/templates/overlays/marketing/CAMPAIGNS.md +3 -0
  135. package/src/templates/overlays/marketing/METRICS.md +3 -0
  136. package/src/templates/overlays/research/FINDINGS.md +3 -0
  137. package/src/templates/overlays/research/SOURCES.md +3 -0
  138. package/src/tool.ts +282 -0
@@ -0,0 +1,38 @@
1
+ import { readRegistry } from '../lib/registry.js';
2
+ import { checkAuthorization } from '../lib/auth.js';
3
+ import { htmlEscape } from '../lib/security.js';
4
+ import { generateInclude } from '../lib/include-generator.js';
5
+ import { triggerRestart } from '../lib/config-restart.js';
6
+ export async function handleSync(ctx) {
7
+ const { workspaceDir, configDir, userId, rpc, logger } = ctx;
8
+ if (!userId) {
9
+ return { text: 'Missing context: userId not available.' };
10
+ }
11
+ const registry = readRegistry(workspaceDir);
12
+ // Auth check (admin tier)
13
+ const auth = checkAuthorization(userId, 'sync', registry);
14
+ if (!auth.authorized) {
15
+ return { text: auth.message ?? 'Not authorized.' };
16
+ }
17
+ try {
18
+ generateInclude(workspaceDir, registry, configDir);
19
+ }
20
+ catch (err) {
21
+ const msg = err instanceof Error ? err.message : String(err);
22
+ return {
23
+ text: `Sync failed: ${htmlEscape(msg)}`,
24
+ parseMode: 'HTML',
25
+ };
26
+ }
27
+ const restartResult = await triggerRestart(rpc, logger);
28
+ const topicCount = Object.keys(registry.topics).length;
29
+ let text = `Include regenerated from ${topicCount} topic(s). Config synced.`;
30
+ if (!restartResult.success && restartResult.fallbackMessage) {
31
+ text += '\n' + restartResult.fallbackMessage;
32
+ }
33
+ return {
34
+ text,
35
+ parseMode: 'HTML',
36
+ };
37
+ }
38
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG1D,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAmB;IAClD,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAE7D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,IAAI,EAAE,wCAAwC,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAE5C,0BAA0B;IAC1B,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1D,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACrB,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,IAAI,iBAAiB,EAAE,CAAC;IACrD,CAAC;IAED,IAAI,CAAC;QACH,eAAe,CAAC,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,OAAO;YACL,IAAI,EAAE,gBAAgB,UAAU,CAAC,GAAG,CAAC,EAAE;YACvC,SAAS,EAAE,MAAM;SAClB,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAExD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC;IACvD,IAAI,IAAI,GAAG,4BAA4B,UAAU,2BAA2B,CAAC;IAE7E,IAAI,CAAC,aAAa,CAAC,OAAO,IAAI,aAAa,CAAC,eAAe,EAAE,CAAC;QAC5D,IAAI,IAAI,IAAI,GAAG,aAAa,CAAC,eAAe,CAAC;IAC/C,CAAC;IAED,OAAO;QACL,IAAI;QACJ,SAAS,EAAE,MAAM;KAClB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CommandContext, CommandResult } from './help.js';
2
+ export declare function handleUpgrade(ctx: CommandContext): Promise<CommandResult>;
3
+ //# sourceMappingURL=upgrade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.d.ts","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/D,wBAAsB,aAAa,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAuD/E"}
@@ -0,0 +1,52 @@
1
+ import * as path from 'node:path';
2
+ import { readRegistry, withRegistry } from '../lib/registry.js';
3
+ import { checkAuthorization } from '../lib/auth.js';
4
+ import { topicKey, CAPSULE_VERSION } from '../lib/types.js';
5
+ import { htmlEscape } from '../lib/security.js';
6
+ import { upgradeCapsule } from '../lib/capsule.js';
7
+ export async function handleUpgrade(ctx) {
8
+ const { workspaceDir, userId, groupId, threadId } = ctx;
9
+ if (!userId || !groupId || !threadId) {
10
+ return { text: 'Missing context: userId, groupId, or threadId not available.' };
11
+ }
12
+ const registry = readRegistry(workspaceDir);
13
+ // Auth check (user tier)
14
+ const auth = checkAuthorization(userId, 'upgrade', registry);
15
+ if (!auth.authorized) {
16
+ return { text: auth.message ?? 'Not authorized.' };
17
+ }
18
+ const key = topicKey(groupId, threadId);
19
+ const entry = registry.topics[key];
20
+ if (!entry) {
21
+ return { text: 'This topic is not registered. Run /topic init first.' };
22
+ }
23
+ if (entry.capsuleVersion >= CAPSULE_VERSION) {
24
+ return {
25
+ text: `Topic <code>${htmlEscape(entry.slug)}</code> is already at capsule version ${CAPSULE_VERSION}. No upgrade needed.`,
26
+ parseMode: 'HTML',
27
+ };
28
+ }
29
+ const projectsBase = path.join(workspaceDir, 'projects');
30
+ const result = upgradeCapsule(projectsBase, entry.slug, entry.type, entry.capsuleVersion);
31
+ if (!result.upgraded) {
32
+ return {
33
+ text: `No upgrade needed for <code>${htmlEscape(entry.slug)}</code>.`,
34
+ parseMode: 'HTML',
35
+ };
36
+ }
37
+ // Update capsule version in registry
38
+ await withRegistry(workspaceDir, (data) => {
39
+ const topic = data.topics[key];
40
+ if (topic) {
41
+ topic.capsuleVersion = result.newVersion;
42
+ }
43
+ });
44
+ const addedList = result.addedFiles.length > 0
45
+ ? `\nAdded files: ${result.addedFiles.map((f) => htmlEscape(f)).join(', ')}`
46
+ : '\nNo new files added.';
47
+ return {
48
+ text: `Topic <code>${htmlEscape(entry.slug)}</code> upgraded from v${entry.capsuleVersion} to v${result.newVersion}.${addedList}`,
49
+ parseMode: 'HTML',
50
+ };
51
+ }
52
+ //# sourceMappingURL=upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../../src/commands/upgrade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export default function register(api: {
2
+ logger: {
3
+ info(msg: string): void;
4
+ warn(msg: string): void;
5
+ error(msg: string): void;
6
+ };
7
+ configDir?: string;
8
+ workspaceDir?: string;
9
+ rpc?: {
10
+ call(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>>;
11
+ } | null;
12
+ pluginConfig?: {
13
+ configDir?: string;
14
+ workspaceDir?: string;
15
+ };
16
+ registerTool(def: {
17
+ name: string;
18
+ description: string;
19
+ parameters: unknown;
20
+ execute(id: string, params: {
21
+ command: string;
22
+ }, context?: Record<string, unknown>): Promise<unknown>;
23
+ }): void;
24
+ }): void;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE;IACpC,MAAM,EAAE;QAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE;QAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;KAAE,GAAG,IAAI,CAAC;IACzG,YAAY,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,YAAY,CAAC,GAAG,EAAE;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,OAAO,CAAC;QACpB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;KACvG,GAAG,IAAI,CAAC;CACV,GAAG,IAAI,CAsCP"}
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ import { Type } from '@sinclair/typebox';
2
+ import { createTopicManagerTool } from './tool.js';
3
+ export default function register(api) {
4
+ const configDir = api.configDir ?? api.pluginConfig?.configDir;
5
+ const workspaceDir = api.workspaceDir ?? api.pluginConfig?.workspaceDir;
6
+ if (!configDir || !workspaceDir) {
7
+ api.logger.error('telegram-manager: configDir or workspaceDir not available. Plugin cannot initialize.');
8
+ return;
9
+ }
10
+ const tool = createTopicManagerTool({
11
+ logger: api.logger,
12
+ configDir,
13
+ workspaceDir,
14
+ rpc: api.rpc,
15
+ });
16
+ api.registerTool({
17
+ name: 'topic_manager',
18
+ description: 'Manage Telegram forum topics as deterministic workcells. Sub-commands: init, doctor, list, status, sync, rename, upgrade, snooze, archive, unarchive, help.',
19
+ parameters: Type.Object({
20
+ command: Type.String({
21
+ description: "Sub-command and arguments (e.g., 'init', 'doctor --all', 'rename new-slug')",
22
+ }),
23
+ }),
24
+ async execute(id, params, context) {
25
+ return tool.execute(id, params, context);
26
+ },
27
+ });
28
+ api.logger.info('telegram-manager plugin loaded');
29
+ }
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAEnD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAYhC;IACC,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,YAAY,EAAE,SAAS,CAAC;IAC/D,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;IAExE,IAAI,CAAC,SAAS,IAAI,CAAC,YAAY,EAAE,CAAC;QAChC,GAAG,CAAC,MAAM,CAAC,KAAK,CACd,sFAAsF,CACvF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,sBAAsB,CAAC;QAClC,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,SAAS;QACT,YAAY;QACZ,GAAG,EAAE,GAAG,CAAC,GAAG;KACb,CAAC,CAAC;IAEH,GAAG,CAAC,YAAY,CAAC;QACf,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,6JAA6J;QAC/J,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC;YACtB,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC;gBACnB,WAAW,EACT,6EAA6E;aAChF,CAAC;SACH,CAAC;QACF,KAAK,CAAC,OAAO,CACX,EAAU,EACV,MAA2B,EAC3B,OAAiC;YAEjC,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;KACF,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { AuditEntry } from './types.js';
2
+ /**
3
+ * Append an audit entry to the audit.jsonl file.
4
+ * Creates the file if it does not exist. Each entry is a single JSON line.
5
+ * File permissions are set to 0600.
6
+ */
7
+ export declare function appendAudit(workspaceDir: string, entry: AuditEntry): void;
8
+ /**
9
+ * Build an AuditEntry with the current timestamp.
10
+ */
11
+ export declare function buildAuditEntry(userId: string, cmd: string, slug: string, detail: string): AuditEntry;
12
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/lib/audit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAK7C;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAazE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,UAAU,CAQZ"}
@@ -0,0 +1,35 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ const AUDIT_FILENAME = 'audit.jsonl';
4
+ const FILE_MODE = 0o600;
5
+ /**
6
+ * Append an audit entry to the audit.jsonl file.
7
+ * Creates the file if it does not exist. Each entry is a single JSON line.
8
+ * File permissions are set to 0600.
9
+ */
10
+ export function appendAudit(workspaceDir, entry) {
11
+ const auditPath = path.join(workspaceDir, 'projects', AUDIT_FILENAME);
12
+ const line = JSON.stringify(entry) + '\n';
13
+ const fd = fs.openSync(auditPath, 'a', FILE_MODE);
14
+ try {
15
+ fs.writeSync(fd, line);
16
+ }
17
+ finally {
18
+ fs.closeSync(fd);
19
+ }
20
+ // Ensure permissions are correct even if file already existed
21
+ fs.chmodSync(auditPath, FILE_MODE);
22
+ }
23
+ /**
24
+ * Build an AuditEntry with the current timestamp.
25
+ */
26
+ export function buildAuditEntry(userId, cmd, slug, detail) {
27
+ return {
28
+ ts: new Date().toISOString(),
29
+ userId,
30
+ cmd,
31
+ slug,
32
+ detail,
33
+ };
34
+ }
35
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/lib/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAGlC,MAAM,cAAc,GAAG,aAAa,CAAC;AACrC,MAAM,SAAS,GAAG,KAAK,CAAC;AAExB;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,YAAoB,EAAE,KAAiB;IACjE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IAE1C,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;IAClD,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;IAED,8DAA8D;IAC9D,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,GAAW,EACX,IAAY,EACZ,MAAc;IAEd,OAAO;QACL,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QAC5B,MAAM;QACN,GAAG;QACH,IAAI;QACJ,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { Registry } from './types.js';
2
+ export declare const AuthTier: {
3
+ readonly User: "User";
4
+ readonly Admin: "Admin";
5
+ };
6
+ export type AuthTier = (typeof AuthTier)[keyof typeof AuthTier];
7
+ /**
8
+ * Get the authorization tier for a command.
9
+ * Defaults to Admin for unknown commands.
10
+ */
11
+ export declare function getCommandTier(command: string): AuthTier;
12
+ export interface AuthResult {
13
+ authorized: boolean;
14
+ message?: string;
15
+ }
16
+ /**
17
+ * Check if a user is authorized to run a command.
18
+ *
19
+ * Logic:
20
+ * - Admin-tier: user must be in topicManagerAdmins
21
+ * - User-tier: user must be in topicAllowFrom OR topicManagerAdmins
22
+ * - Special case for init: if topicManagerAdmins is empty (first-time setup),
23
+ * allow anyone — the first user to init becomes the default admin.
24
+ */
25
+ export declare function checkAuthorization(userId: string, command: string, registry: Registry, topicAllowFrom?: string[]): AuthResult;
26
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,eAAO,MAAM,QAAQ;;;CAGX,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAuBhE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,CAMxD;AAID,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,UAAU,CA8BZ"}
@@ -0,0 +1,73 @@
1
+ // ── Authorization tiers ────────────────────────────────────────────────
2
+ export const AuthTier = {
3
+ User: 'User',
4
+ Admin: 'Admin',
5
+ };
6
+ // ── Command-to-tier mapping ────────────────────────────────────────────
7
+ const ADMIN_COMMANDS = new Set([
8
+ 'doctor --all',
9
+ 'doctor-all',
10
+ 'list',
11
+ 'sync',
12
+ 'rename',
13
+ 'archive',
14
+ 'unarchive',
15
+ ]);
16
+ const USER_COMMANDS = new Set([
17
+ 'init',
18
+ 'doctor',
19
+ 'status',
20
+ 'help',
21
+ 'upgrade',
22
+ 'snooze',
23
+ ]);
24
+ /**
25
+ * Get the authorization tier for a command.
26
+ * Defaults to Admin for unknown commands.
27
+ */
28
+ export function getCommandTier(command) {
29
+ const normalized = command.toLowerCase().trim();
30
+ if (USER_COMMANDS.has(normalized))
31
+ return AuthTier.User;
32
+ if (ADMIN_COMMANDS.has(normalized))
33
+ return AuthTier.Admin;
34
+ // Unknown commands default to admin tier (principle of least privilege)
35
+ return AuthTier.Admin;
36
+ }
37
+ /**
38
+ * Check if a user is authorized to run a command.
39
+ *
40
+ * Logic:
41
+ * - Admin-tier: user must be in topicManagerAdmins
42
+ * - User-tier: user must be in topicAllowFrom OR topicManagerAdmins
43
+ * - Special case for init: if topicManagerAdmins is empty (first-time setup),
44
+ * allow anyone — the first user to init becomes the default admin.
45
+ */
46
+ export function checkAuthorization(userId, command, registry, topicAllowFrom) {
47
+ const tier = getCommandTier(command);
48
+ const admins = registry.topicManagerAdmins;
49
+ // First-user bootstrap: if no admins set yet, allow anyone for init
50
+ if (command === 'init' && admins.length === 0) {
51
+ return { authorized: true };
52
+ }
53
+ const isAdmin = admins.includes(userId);
54
+ if (tier === AuthTier.Admin) {
55
+ if (isAdmin)
56
+ return { authorized: true };
57
+ return {
58
+ authorized: false,
59
+ message: 'Not authorized. Ask a telegram-manager admin to run this command.',
60
+ };
61
+ }
62
+ // User tier: allowed if admin or in topicAllowFrom
63
+ if (isAdmin)
64
+ return { authorized: true };
65
+ if (topicAllowFrom && topicAllowFrom.includes(userId)) {
66
+ return { authorized: true };
67
+ }
68
+ return {
69
+ authorized: false,
70
+ message: 'Not authorized. Ask a telegram-manager admin to run this command.',
71
+ };
72
+ }
73
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAEA,0EAA0E;AAE1E,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;CACN,CAAC;AAIX,0EAA0E;AAE1E,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,cAAc;IACd,YAAY;IACZ,MAAM;IACN,MAAM;IACN,QAAQ;IACR,SAAS;IACT,WAAW;CACZ,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,SAAS;IACT,QAAQ;CACT,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAChD,IAAI,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAC;IACxD,IAAI,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC;QAAE,OAAO,QAAQ,CAAC,KAAK,CAAC;IAC1D,wEAAwE;IACxE,OAAO,QAAQ,CAAC,KAAK,CAAC;AACxB,CAAC;AASD;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAc,EACd,OAAe,EACf,QAAkB,EAClB,cAAyB;IAEzB,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,QAAQ,CAAC,kBAAkB,CAAC;IAE3C,oEAAoE;IACpE,IAAI,OAAO,KAAK,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAExC,IAAI,IAAI,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,OAAO;YAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QACzC,OAAO;YACL,UAAU,EAAE,KAAK;YACjB,OAAO,EAAE,mEAAmE;SAC7E,CAAC;IACJ,CAAC;IAED,mDAAmD;IACnD,IAAI,OAAO;QAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAEzC,IAAI,cAAc,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO;QACL,UAAU,EAAE,KAAK;QACjB,OAAO,EAAE,mEAAmE;KAC7E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { TopicType } from './types.js';
2
+ /**
3
+ * Scaffold a new capsule directory with base kit + type overlays.
4
+ * Uses fs.mkdirSync with exclusive flag as the atomic reservation mechanism.
5
+ * Throws if the directory already exists (collision).
6
+ */
7
+ export declare function scaffoldCapsule(projectsBase: string, slug: string, type: TopicType): void;
8
+ export interface UpgradeResult {
9
+ upgraded: boolean;
10
+ newVersion: number;
11
+ addedFiles: string[];
12
+ }
13
+ /**
14
+ * Upgrade an existing capsule to the latest template version.
15
+ * Adds missing files without overwriting existing ones.
16
+ */
17
+ export declare function upgradeCapsule(projectsBase: string, slug: string, type: TopicType, currentVersion: number): UpgradeResult;
18
+ export interface CapsuleValidation {
19
+ missing: string[];
20
+ present: string[];
21
+ }
22
+ /**
23
+ * Validate that a capsule has all expected files.
24
+ * Returns lists of present and missing files.
25
+ */
26
+ export declare function validateCapsule(projectsBase: string, slug: string, type: TopicType): CapsuleValidation;
27
+ //# sourceMappingURL=capsule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capsule.d.ts","sourceRoot":"","sources":["../../src/lib/capsule.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAuD5C;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,GACd,IAAI,CAkCN;AAID,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,EACf,cAAc,EAAE,MAAM,GACrB,aAAa,CA+Cf;AAID,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,GACd,iBAAiB,CAqBnB"}
@@ -0,0 +1,130 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { BASE_FILES, OVERLAY_FILES, CAPSULE_VERSION } from './types.js';
4
+ import { jailCheck, rejectSymlink } from './security.js';
5
+ // ── Template content (embedded string constants) ───────────────────────
6
+ // These are the source-of-truth defaults, matching src/templates/.
7
+ const BASE_TEMPLATES = {
8
+ 'README.md': (slug) => `# ${slug}\n\n_Describe what this topic is about._\n`,
9
+ 'STATUS.md': (slug) => `# Status: ${slug}\n\n## Last done (UTC)\n\n${new Date().toISOString()}\n\n_No work recorded yet._\n\n## Next 3 actions\n\n1. [T-1] _Define first task in TODO.md_\n2. [T-2] _Define second task in TODO.md_\n3. [T-3] _Define third task in TODO.md_\n`,
10
+ 'TODO.md': (slug) => `# TODO: ${slug}\n\n## Backlog\n\n- [T-1] _First task placeholder — replace with actual task_\n- [T-2] _Second task placeholder — replace with actual task_\n- [T-3] _Third task placeholder — replace with actual task_\n\n## Completed\n\n_None yet._\n`,
11
+ 'COMMANDS.md': (slug) => `# Commands: ${slug}\n\n_Build, deploy, test, and other commands for this topic. Kept here so they're not lost on reset._\n`,
12
+ 'LINKS.md': (slug) => `# Links: ${slug}\n\n_URLs, paths, and service endpoints for this topic._\n`,
13
+ 'CRON.md': (slug) => `# Cron: ${slug}\n\n_Cron job IDs and schedules for this topic._\n`,
14
+ 'NOTES.md': (slug) => `# Notes: ${slug}\n\n_Anything worth remembering about this topic._\n`,
15
+ };
16
+ const OVERLAY_TEMPLATES = {
17
+ 'ARCHITECTURE.md': (slug) => `# Architecture: ${slug}\n\n_Components, data flow, dependencies, and design decisions._\n`,
18
+ 'DEPLOY.md': (slug) => `# Deployment: ${slug}\n\n_Environments, deployment steps, rollback procedures, and infra details._\n`,
19
+ 'SOURCES.md': (slug) => `# Sources: ${slug}\n\n_Papers, articles, datasets, APIs, and other reference material._\n`,
20
+ 'FINDINGS.md': (slug) => `# Findings: ${slug}\n\n_Conclusions, insights, data summaries, and recommendations._\n`,
21
+ 'CAMPAIGNS.md': (slug) => `# Campaigns: ${slug}\n\n_Active campaigns, target audiences, channels, timelines, and budgets._\n`,
22
+ 'METRICS.md': (slug) => `# Metrics: ${slug}\n\n_KPIs, conversion rates, engagement stats, and performance data._\n`,
23
+ };
24
+ // ── File permissions ───────────────────────────────────────────────────
25
+ const CAPSULE_FILE_MODE = 0o640;
26
+ // ── Scaffold ───────────────────────────────────────────────────────────
27
+ /**
28
+ * Scaffold a new capsule directory with base kit + type overlays.
29
+ * Uses fs.mkdirSync with exclusive flag as the atomic reservation mechanism.
30
+ * Throws if the directory already exists (collision).
31
+ */
32
+ export function scaffoldCapsule(projectsBase, slug, type) {
33
+ const capsuleDir = path.join(projectsBase, slug);
34
+ // Path jail check
35
+ if (!jailCheck(projectsBase, slug)) {
36
+ throw new Error(`Path escapes projects directory: ${slug}`);
37
+ }
38
+ // Symlink check on parent
39
+ if (rejectSymlink(projectsBase)) {
40
+ throw new Error(`Projects base is a symlink: ${projectsBase}`);
41
+ }
42
+ // Atomic directory creation (exclusive)
43
+ fs.mkdirSync(capsuleDir, { recursive: false });
44
+ // Write base files
45
+ for (const file of BASE_FILES) {
46
+ const templateFn = BASE_TEMPLATES[file];
47
+ if (templateFn) {
48
+ const filePath = path.join(capsuleDir, file);
49
+ fs.writeFileSync(filePath, templateFn(slug), { mode: CAPSULE_FILE_MODE });
50
+ }
51
+ }
52
+ // Write overlay files for the type
53
+ const overlays = OVERLAY_FILES[type];
54
+ for (const file of overlays) {
55
+ const templateFn = OVERLAY_TEMPLATES[file];
56
+ if (templateFn) {
57
+ const filePath = path.join(capsuleDir, file);
58
+ fs.writeFileSync(filePath, templateFn(slug), { mode: CAPSULE_FILE_MODE });
59
+ }
60
+ }
61
+ }
62
+ /**
63
+ * Upgrade an existing capsule to the latest template version.
64
+ * Adds missing files without overwriting existing ones.
65
+ */
66
+ export function upgradeCapsule(projectsBase, slug, type, currentVersion) {
67
+ if (currentVersion >= CAPSULE_VERSION) {
68
+ return { upgraded: false, newVersion: currentVersion, addedFiles: [] };
69
+ }
70
+ const capsuleDir = path.join(projectsBase, slug);
71
+ if (!jailCheck(projectsBase, slug)) {
72
+ throw new Error(`Path escapes projects directory: ${slug}`);
73
+ }
74
+ if (rejectSymlink(capsuleDir)) {
75
+ throw new Error(`Capsule directory is a symlink: ${capsuleDir}`);
76
+ }
77
+ const addedFiles = [];
78
+ // Add missing base files
79
+ for (const file of BASE_FILES) {
80
+ const filePath = path.join(capsuleDir, file);
81
+ if (!fs.existsSync(filePath)) {
82
+ const templateFn = BASE_TEMPLATES[file];
83
+ if (templateFn) {
84
+ fs.writeFileSync(filePath, templateFn(slug), { mode: CAPSULE_FILE_MODE });
85
+ addedFiles.push(file);
86
+ }
87
+ }
88
+ }
89
+ // Add missing overlay files
90
+ const overlays = OVERLAY_FILES[type];
91
+ for (const file of overlays) {
92
+ const filePath = path.join(capsuleDir, file);
93
+ if (!fs.existsSync(filePath)) {
94
+ const templateFn = OVERLAY_TEMPLATES[file];
95
+ if (templateFn) {
96
+ fs.writeFileSync(filePath, templateFn(slug), { mode: CAPSULE_FILE_MODE });
97
+ addedFiles.push(file);
98
+ }
99
+ }
100
+ }
101
+ return {
102
+ upgraded: true,
103
+ newVersion: CAPSULE_VERSION,
104
+ addedFiles,
105
+ };
106
+ }
107
+ /**
108
+ * Validate that a capsule has all expected files.
109
+ * Returns lists of present and missing files.
110
+ */
111
+ export function validateCapsule(projectsBase, slug, type) {
112
+ const capsuleDir = path.join(projectsBase, slug);
113
+ if (!jailCheck(projectsBase, slug)) {
114
+ throw new Error(`Path escapes projects directory: ${slug}`);
115
+ }
116
+ const expectedFiles = [...BASE_FILES, ...OVERLAY_FILES[type]];
117
+ const missing = [];
118
+ const present = [];
119
+ for (const file of expectedFiles) {
120
+ const filePath = path.join(capsuleDir, file);
121
+ if (fs.existsSync(filePath)) {
122
+ present.push(file);
123
+ }
124
+ else {
125
+ missing.push(file);
126
+ }
127
+ }
128
+ return { missing, present };
129
+ }
130
+ //# sourceMappingURL=capsule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capsule.js","sourceRoot":"","sources":["../../src/lib/capsule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { RpcInterface, Logger } from './types.js';
2
+ export type { RpcInterface, Logger };
3
+ export interface RestartResult {
4
+ success: boolean;
5
+ fallbackMessage?: string;
6
+ }
7
+ /**
8
+ * Trigger a Gateway restart via config.patch no-op.
9
+ *
10
+ * - Enforces a 60-second cooldown between calls
11
+ * - Retries up to 3 times on baseHash mismatch with exponential backoff
12
+ * - Falls back to a user message if RPC is unavailable
13
+ */
14
+ export declare function triggerRestart(rpc: RpcInterface | null | undefined, logger: Logger): Promise<RestartResult>;
15
+ /**
16
+ * Check if configWrites is enabled in the plugin config via RPC.
17
+ */
18
+ export declare function getConfigWrites(rpc: RpcInterface | null | undefined): Promise<boolean>;
19
+ /**
20
+ * Reset the cooldown timer (for testing purposes).
21
+ */
22
+ export declare function resetCooldown(): void;
23
+ //# sourceMappingURL=config-restart.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-restart.d.ts","sourceRoot":"","sources":["../../src/lib/config-restart.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEvD,YAAY,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC;AAErC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAcD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,EACpC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CAqFxB;AAsBD;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAW5F;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}