crewly 1.20.209 → 1.20.211

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 (93) hide show
  1. package/config/skills/agent/core/app-data/SKILL.md +117 -0
  2. package/config/skills/agent/core/app-data/execute.sh +141 -0
  3. package/config/skills/agent/core/app-data/execute.test.sh +108 -0
  4. package/config/skills/agent/core/publish-app/SKILL.md +248 -0
  5. package/config/skills/agent/core/publish-app/execute.sh +302 -0
  6. package/config/skills/agent/core/publish-app/execute.test.sh +205 -0
  7. package/dist/backend/backend/src/constants.d.ts +115 -0
  8. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  9. package/dist/backend/backend/src/constants.js +115 -0
  10. package/dist/backend/backend/src/constants.js.map +1 -1
  11. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +55 -0
  12. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts.map +1 -0
  13. package/dist/backend/backend/src/controllers/apps/apps.controller.js +131 -0
  14. package/dist/backend/backend/src/controllers/apps/apps.controller.js.map +1 -0
  15. package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts +53 -0
  16. package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts.map +1 -0
  17. package/dist/backend/backend/src/controllers/apps/apps.routes.js +108 -0
  18. package/dist/backend/backend/src/controllers/apps/apps.routes.js.map +1 -0
  19. package/dist/backend/backend/src/index.d.ts +1 -0
  20. package/dist/backend/backend/src/index.d.ts.map +1 -1
  21. package/dist/backend/backend/src/index.js +57 -5
  22. package/dist/backend/backend/src/index.js.map +1 -1
  23. package/dist/backend/backend/src/middleware/body-parser-except.d.ts +25 -0
  24. package/dist/backend/backend/src/middleware/body-parser-except.d.ts.map +1 -0
  25. package/dist/backend/backend/src/middleware/body-parser-except.js +33 -0
  26. package/dist/backend/backend/src/middleware/body-parser-except.js.map +1 -0
  27. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  28. package/dist/backend/backend/src/routes/api.routes.js +4 -0
  29. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  30. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  31. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
  32. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  33. package/dist/backend/backend/src/services/apps/app-open-link.d.ts +61 -0
  34. package/dist/backend/backend/src/services/apps/app-open-link.d.ts.map +1 -0
  35. package/dist/backend/backend/src/services/apps/app-open-link.js +112 -0
  36. package/dist/backend/backend/src/services/apps/app-open-link.js.map +1 -0
  37. package/dist/backend/backend/src/services/apps/app-wake-message.d.ts +136 -0
  38. package/dist/backend/backend/src/services/apps/app-wake-message.d.ts.map +1 -0
  39. package/dist/backend/backend/src/services/apps/app-wake-message.js +253 -0
  40. package/dist/backend/backend/src/services/apps/app-wake-message.js.map +1 -0
  41. package/dist/backend/backend/src/services/apps/app-wake.service.d.ts +145 -0
  42. package/dist/backend/backend/src/services/apps/app-wake.service.d.ts.map +1 -0
  43. package/dist/backend/backend/src/services/apps/app-wake.service.js +455 -0
  44. package/dist/backend/backend/src/services/apps/app-wake.service.js.map +1 -0
  45. package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts +74 -0
  46. package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts.map +1 -0
  47. package/dist/backend/backend/src/services/apps/apps-cloud.client.js +120 -0
  48. package/dist/backend/backend/src/services/apps/apps-cloud.client.js.map +1 -0
  49. package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts +125 -0
  50. package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts.map +1 -0
  51. package/dist/backend/backend/src/services/apps/apps-registry.service.js +192 -0
  52. package/dist/backend/backend/src/services/apps/apps-registry.service.js.map +1 -0
  53. package/dist/backend/backend/src/services/apps/apps.service.d.ts +466 -0
  54. package/dist/backend/backend/src/services/apps/apps.service.d.ts.map +1 -0
  55. package/dist/backend/backend/src/services/apps/apps.service.js +740 -0
  56. package/dist/backend/backend/src/services/apps/apps.service.js.map +1 -0
  57. package/dist/backend/backend/src/services/apps/apps.wiring.d.ts +97 -0
  58. package/dist/backend/backend/src/services/apps/apps.wiring.d.ts.map +1 -0
  59. package/dist/backend/backend/src/services/apps/apps.wiring.js +153 -0
  60. package/dist/backend/backend/src/services/apps/apps.wiring.js.map +1 -0
  61. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +3 -1
  63. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  64. package/dist/backend/backend/src/services/core/logger.service.d.ts +5 -0
  65. package/dist/backend/backend/src/services/core/logger.service.d.ts.map +1 -1
  66. package/dist/backend/backend/src/services/core/logger.service.js +8 -0
  67. package/dist/backend/backend/src/services/core/logger.service.js.map +1 -1
  68. package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
  69. package/dist/backend/backend/src/services/slack/slack-thread-context.service.js +3 -1
  70. package/dist/backend/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
  71. package/dist/backend/build-info.json +2 -2
  72. package/dist/cli/backend/src/constants.d.ts +115 -0
  73. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  74. package/dist/cli/backend/src/constants.js +115 -0
  75. package/dist/cli/backend/src/constants.js.map +1 -1
  76. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  77. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
  78. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  79. package/dist/cli/backend/src/services/apps/app-open-link.d.ts +61 -0
  80. package/dist/cli/backend/src/services/apps/app-open-link.d.ts.map +1 -0
  81. package/dist/cli/backend/src/services/apps/app-open-link.js +112 -0
  82. package/dist/cli/backend/src/services/apps/app-open-link.js.map +1 -0
  83. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  84. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +3 -1
  85. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  86. package/dist/cli/backend/src/services/core/logger.service.d.ts +5 -0
  87. package/dist/cli/backend/src/services/core/logger.service.d.ts.map +1 -1
  88. package/dist/cli/backend/src/services/core/logger.service.js +8 -0
  89. package/dist/cli/backend/src/services/core/logger.service.js.map +1 -1
  90. package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
  91. package/dist/cli/backend/src/services/slack/slack-thread-context.service.js +3 -1
  92. package/dist/cli/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
  93. package/package.json +1 -1
@@ -0,0 +1,120 @@
1
+ /**
2
+ * AppsCloudClient — this instance's calls to the Crewly Apps agent API
3
+ * (`<cloudUrl>/api/apps/v1`, crewly-services apps/SPEC.md §3.1).
4
+ *
5
+ * Authenticates with the Cloud access token the {@link CloudClientService}
6
+ * holds and refreshes, bound to this instance (`X-Crewly-Instance`) and
7
+ * attributed to the calling agent (`X-Crewly-Agent`). Agents never see the
8
+ * token: they reach this through `/api/apps` (specs/2026-10-04-crewly-apps-p2.md).
9
+ *
10
+ * @module services/apps/apps-cloud.client
11
+ */
12
+ import { CREWLY_APPS_CONSTANTS } from '../../constants.js';
13
+ import { CloudClientService } from '../cloud/cloud-client.service.js';
14
+ const C = CREWLY_APPS_CONSTANTS;
15
+ /** A failed Apps call: HTTP status and a stable code for the controller and skills. */
16
+ export class AppsCloudError extends Error {
17
+ status;
18
+ code;
19
+ constructor(status, code, message) {
20
+ super(message);
21
+ this.status = status;
22
+ this.code = code;
23
+ this.name = 'AppsCloudError';
24
+ }
25
+ }
26
+ /**
27
+ * Typed wrapper over the Apps agent API.
28
+ */
29
+ export class AppsCloudClient {
30
+ deps;
31
+ cloud;
32
+ fetchImpl;
33
+ constructor(deps) {
34
+ this.deps = deps;
35
+ this.cloud = deps.cloud ?? CloudClientService.getInstance();
36
+ this.fetchImpl = deps.fetchImpl ?? fetch;
37
+ }
38
+ /**
39
+ * Whether a Cloud login is present (a call can be attempted).
40
+ *
41
+ * @returns True when connected with a token and URL
42
+ */
43
+ isAvailable() {
44
+ return this.cloud.isConnected() && !!this.cloud.getToken() && !!this.cloud.getCloudUrl();
45
+ }
46
+ /**
47
+ * Call the Apps API and return its `data`.
48
+ *
49
+ * A 401 refreshes the Cloud token once and retries. Cloud's
50
+ * `{ success:false, error, code }` becomes an {@link AppsCloudError} with
51
+ * Cloud's status and code. The token is never part of an error.
52
+ *
53
+ * @param method - HTTP method
54
+ * @param path - Path under `/api/apps/v1` (starts with `/`)
55
+ * @param opts - Body, query, agent attribution
56
+ * @returns The response `data`
57
+ * @throws AppsCloudError not_logged_in / instance_unknown / network / Cloud's code
58
+ */
59
+ async request(method, path, opts = {}) {
60
+ if (!this.isAvailable()) {
61
+ throw new AppsCloudError(409, C.ERROR_CODES.NOT_LOGGED_IN, 'This machine is not signed in to Crewly Cloud. Run `crewly cloud login`.');
62
+ }
63
+ const instanceId = await this.deps.instanceId();
64
+ if (!instanceId) {
65
+ throw new AppsCloudError(409, C.ERROR_CODES.NO_INSTANCE, 'This machine has no Crewly Cloud instance id yet. Sign in to Crewly Cloud and try again in a minute.');
66
+ }
67
+ let res = await this.send(method, path, opts, instanceId);
68
+ if (res.status === 401 && (await this.cloud.tryRefreshToken().catch(() => false))) {
69
+ res = await this.send(method, path, opts, instanceId);
70
+ }
71
+ const json = await AppsCloudClient.readJson(res);
72
+ if (res.ok && json && json.success !== false)
73
+ return json.data;
74
+ const code = typeof json?.code === 'string' ? json.code : res.status === 401 ? C.ERROR_CODES.NOT_LOGGED_IN : `http_${res.status}`;
75
+ const message = typeof json?.error === 'string'
76
+ ? json.error
77
+ : res.status === 401
78
+ ? 'Crewly Cloud rejected the session. Run `crewly cloud login` again.'
79
+ : `Crewly Apps request failed (${res.status}).`;
80
+ throw new AppsCloudError(res.status === 401 ? 409 : res.status, code, message);
81
+ }
82
+ static async readJson(res) {
83
+ try {
84
+ const parsed = await res.json();
85
+ return parsed && typeof parsed === 'object' ? parsed : null;
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ }
91
+ async send(method, path, opts, instanceId) {
92
+ const base = `${(this.cloud.getCloudUrl() ?? '').replace(/\/+$/, '')}${C.CLOUD_PATH}`;
93
+ const url = new URL(`${base}${path}`);
94
+ for (const [k, v] of Object.entries(opts.query ?? {})) {
95
+ if (v !== undefined && v !== '')
96
+ url.searchParams.set(k, String(v));
97
+ }
98
+ const headers = {
99
+ Authorization: `Bearer ${this.cloud.getToken() ?? ''}`,
100
+ 'X-Crewly-Instance': instanceId,
101
+ };
102
+ if (opts.agent)
103
+ headers['X-Crewly-Agent'] = opts.agent;
104
+ if (opts.body !== undefined)
105
+ headers['Content-Type'] = 'application/json';
106
+ try {
107
+ return await this.fetchImpl(url.toString(), {
108
+ method,
109
+ headers,
110
+ ...(opts.body !== undefined ? { body: JSON.stringify(opts.body) } : {}),
111
+ signal: AbortSignal.timeout(opts.timeoutMs ?? C.REQUEST_TIMEOUT_MS),
112
+ });
113
+ }
114
+ catch (err) {
115
+ const why = err instanceof Error ? err.name : 'error';
116
+ throw new AppsCloudError(502, C.ERROR_CODES.NETWORK, `Could not reach Crewly Apps (${why}). Try again shortly.`);
117
+ }
118
+ }
119
+ }
120
+ //# sourceMappingURL=apps-cloud.client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-cloud.client.js","sourceRoot":"","sources":["../../../../../../backend/src/services/apps/apps-cloud.client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * AppsRegistryService — the apps this instance published, kept in
3
+ * `<CREWLY_HOME>/apps/registry.json`.
4
+ *
5
+ * It answers two questions: which app an agent's publish goes to (so the
6
+ * same agent republishing the same directory lands on the same app), and
7
+ * which agent to wake when an app changes. It also keeps each app's change
8
+ * cursor for the poller (specs/2026-10-04-crewly-apps-p2.md §2, §5).
9
+ *
10
+ * @module services/apps/apps-registry.service
11
+ */
12
+ /** One app this instance published. */
13
+ export interface AppRegistryEntry {
14
+ appId: string;
15
+ name: string;
16
+ url: string;
17
+ /** The agent woken for this app's changes (the last publisher); null = orchestrator */
18
+ agentSession: string | null;
19
+ /** Absolute source directory or file it was published from */
20
+ source: string | null;
21
+ currentVersion: number | null;
22
+ /** Last change seq handled by the poller; null until it first reads the head */
23
+ cursor: number | null;
24
+ createdAt: string;
25
+ updatedAt: string;
26
+ /** Gone from Cloud (404): no longer polled */
27
+ deleted?: boolean;
28
+ /** Last successful wake per recipient (session, or the orchestrator key), epoch ms: the cooldown survives a restart */
29
+ wakes?: Record<string, number>;
30
+ /** Seqs above `cursor` already delivered (another batch for this app is still pending): skipped when re-read */
31
+ delivered?: number[];
32
+ /** Visitor-triggered wakes on a UTC day, and visitor submissions not delivered over the daily cap (P3 §3) */
33
+ visitorWakes?: VisitorWakeState;
34
+ }
35
+ /** The daily cap on visitor-triggered wakes (P3 §3). */
36
+ export interface VisitorWakeState {
37
+ /** UTC day `YYYY-MM-DD` that `count` belongs to */
38
+ day: string;
39
+ /** Visitor-triggered wakes delivered that day */
40
+ count: number;
41
+ /** Visitor submissions counted but not delivered (over the cap), not yet reported to the agent */
42
+ skipped: number;
43
+ }
44
+ /** What to look an app up by when publishing. */
45
+ export interface AppLookup {
46
+ appId?: string;
47
+ agentSession?: string | null;
48
+ source?: string | null;
49
+ name?: string | null;
50
+ }
51
+ /**
52
+ * File-backed registry. All writes are serialised in-process.
53
+ */
54
+ export declare class AppsRegistryService {
55
+ private readonly file;
56
+ private data;
57
+ private chain;
58
+ /**
59
+ * @param crewlyHome - CREWLY_HOME directory
60
+ */
61
+ constructor(crewlyHome: string);
62
+ private load;
63
+ private mutate;
64
+ /**
65
+ * Every app, deleted ones included.
66
+ *
67
+ * @returns Copies of the entries
68
+ */
69
+ list(): Promise<AppRegistryEntry[]>;
70
+ /**
71
+ * One app by id.
72
+ *
73
+ * @param appId - App id
74
+ * @returns A copy, or null
75
+ */
76
+ get(appId: string): Promise<AppRegistryEntry | null>;
77
+ /**
78
+ * The app a publish should go to: explicit id; else the same agent and
79
+ * source; else the same agent and name (case-insensitive). Deleted apps
80
+ * never match implicitly.
81
+ *
82
+ * @param q - Lookup keys
83
+ * @returns The entry, or null (create a new app)
84
+ */
85
+ find(q: AppLookup): Promise<AppRegistryEntry | null>;
86
+ /**
87
+ * Insert or update an entry (fields given replace the stored ones).
88
+ *
89
+ * @param appId - App id
90
+ * @param patch - Fields to set
91
+ * @returns The stored entry
92
+ */
93
+ upsert(appId: string, patch: Partial<Omit<AppRegistryEntry, 'appId'>>): Promise<AppRegistryEntry>;
94
+ /**
95
+ * Store the poller's progress: the cursor and the seqs above it that were
96
+ * already delivered (no-op for an unknown app or no change).
97
+ *
98
+ * @param appId - App id
99
+ * @param cursor - Safe cursor (before every undelivered change)
100
+ * @param delivered - Delivered seqs above the cursor
101
+ */
102
+ setProgress(appId: string, cursor: number, delivered: number[]): Promise<void>;
103
+ /**
104
+ * Record a successful wake for the cooldown.
105
+ *
106
+ * @param appId - App id
107
+ * @param recipient - Session or orchestrator key
108
+ * @param at - Epoch ms
109
+ */
110
+ setLastWake(appId: string, recipient: string, at: number): Promise<void>;
111
+ /**
112
+ * Store the visitor-wake cap state (P3 §3).
113
+ *
114
+ * @param appId - App id
115
+ * @param state - Day, wakes that day, submissions skipped and not yet reported
116
+ */
117
+ setVisitorWakes(appId: string, state: VisitorWakeState): Promise<void>;
118
+ /**
119
+ * Mark an app gone from Cloud.
120
+ *
121
+ * @param appId - App id
122
+ */
123
+ markDeleted(appId: string): Promise<void>;
124
+ }
125
+ //# sourceMappingURL=apps-registry.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-registry.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/apps/apps-registry.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,uCAAuC;AACvC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,uFAAuF;IACvF,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,8DAA8D;IAC9D,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,gFAAgF;IAChF,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,uHAAuH;IACvH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,gHAAgH;IAChH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,6GAA6G;IAC7G,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACjC;AAED,wDAAwD;AACxD,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;IACZ,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,iDAAiD;AACjD,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,KAAK,CAAuC;IAEpD;;OAEG;gBACS,UAAU,EAAE,MAAM;YAIhB,IAAI;IAQlB,OAAO,CAAC,MAAM;IAYd;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAKzC;;;;;OAKG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAM1D;;;;;;;OAOG;IACG,IAAI,CAAC,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAgB1D;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAwBjG;;;;;;;OAOG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAepF;;;;;;OAMG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9E;;;;;OAKG;IACG,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5E;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAShD"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * AppsRegistryService — the apps this instance published, kept in
3
+ * `<CREWLY_HOME>/apps/registry.json`.
4
+ *
5
+ * It answers two questions: which app an agent's publish goes to (so the
6
+ * same agent republishing the same directory lands on the same app), and
7
+ * which agent to wake when an app changes. It also keeps each app's change
8
+ * cursor for the poller (specs/2026-10-04-crewly-apps-p2.md §2, §5).
9
+ *
10
+ * @module services/apps/apps-registry.service
11
+ */
12
+ import { promises as fs } from 'fs';
13
+ import path from 'path';
14
+ import { CREWLY_APPS_CONSTANTS } from '../../constants.js';
15
+ import { atomicWriteJson, safeReadJson } from '../../utils/file-io.utils.js';
16
+ /**
17
+ * File-backed registry. All writes are serialised in-process.
18
+ */
19
+ export class AppsRegistryService {
20
+ file;
21
+ data = null;
22
+ chain = Promise.resolve();
23
+ /**
24
+ * @param crewlyHome - CREWLY_HOME directory
25
+ */
26
+ constructor(crewlyHome) {
27
+ this.file = path.join(crewlyHome, CREWLY_APPS_CONSTANTS.REGISTRY_DIR, CREWLY_APPS_CONSTANTS.REGISTRY_FILE);
28
+ }
29
+ async load() {
30
+ if (!this.data) {
31
+ const raw = await safeReadJson(this.file, { apps: {} });
32
+ this.data = raw && typeof raw === 'object' && raw.apps && typeof raw.apps === 'object' ? raw : { apps: {} };
33
+ }
34
+ return this.data;
35
+ }
36
+ mutate(fn) {
37
+ const run = this.chain.then(async () => {
38
+ const d = await this.load();
39
+ const out = fn(d);
40
+ await fs.mkdir(path.dirname(this.file), { recursive: true });
41
+ await atomicWriteJson(this.file, d);
42
+ return out;
43
+ });
44
+ this.chain = run.catch(() => undefined);
45
+ return run;
46
+ }
47
+ /**
48
+ * Every app, deleted ones included.
49
+ *
50
+ * @returns Copies of the entries
51
+ */
52
+ async list() {
53
+ const d = await this.load();
54
+ return Object.values(d.apps).map((e) => ({ ...e }));
55
+ }
56
+ /**
57
+ * One app by id.
58
+ *
59
+ * @param appId - App id
60
+ * @returns A copy, or null
61
+ */
62
+ async get(appId) {
63
+ const d = await this.load();
64
+ const e = d.apps[appId];
65
+ return e ? { ...e } : null;
66
+ }
67
+ /**
68
+ * The app a publish should go to: explicit id; else the same agent and
69
+ * source; else the same agent and name (case-insensitive). Deleted apps
70
+ * never match implicitly.
71
+ *
72
+ * @param q - Lookup keys
73
+ * @returns The entry, or null (create a new app)
74
+ */
75
+ async find(q) {
76
+ const d = await this.load();
77
+ if (q.appId)
78
+ return d.apps[q.appId] ? { ...d.apps[q.appId] } : null;
79
+ const mine = Object.values(d.apps).filter((e) => !e.deleted && (e.agentSession ?? null) === (q.agentSession ?? null));
80
+ if (q.source) {
81
+ const bySource = mine.find((e) => e.source === q.source);
82
+ if (bySource)
83
+ return { ...bySource };
84
+ }
85
+ if (q.name) {
86
+ const n = q.name.trim().toLowerCase();
87
+ const byName = mine.find((e) => e.name.trim().toLowerCase() === n);
88
+ if (byName)
89
+ return { ...byName };
90
+ }
91
+ return null;
92
+ }
93
+ /**
94
+ * Insert or update an entry (fields given replace the stored ones).
95
+ *
96
+ * @param appId - App id
97
+ * @param patch - Fields to set
98
+ * @returns The stored entry
99
+ */
100
+ upsert(appId, patch) {
101
+ return this.mutate((d) => {
102
+ const now = new Date().toISOString();
103
+ const prev = d.apps[appId];
104
+ const next = {
105
+ appId,
106
+ name: patch.name ?? prev?.name ?? appId,
107
+ url: patch.url ?? prev?.url ?? `${CREWLY_APPS_CONSTANTS.APPS_ORIGIN}/${appId}`,
108
+ agentSession: patch.agentSession !== undefined ? patch.agentSession : prev?.agentSession ?? null,
109
+ source: patch.source !== undefined ? patch.source : prev?.source ?? null,
110
+ currentVersion: patch.currentVersion !== undefined ? patch.currentVersion : prev?.currentVersion ?? null,
111
+ cursor: patch.cursor !== undefined ? patch.cursor : prev?.cursor ?? null,
112
+ createdAt: prev?.createdAt ?? now,
113
+ updatedAt: now,
114
+ ...(patch.deleted !== undefined ? { deleted: patch.deleted } : prev?.deleted ? { deleted: prev.deleted } : {}),
115
+ ...(prev?.wakes ? { wakes: prev.wakes } : {}),
116
+ ...(prev?.visitorWakes ? { visitorWakes: prev.visitorWakes } : {}),
117
+ ...(prev?.delivered && patch.cursor === undefined ? { delivered: prev.delivered } : {}),
118
+ };
119
+ d.apps[appId] = next;
120
+ return { ...next };
121
+ });
122
+ }
123
+ /**
124
+ * Store the poller's progress: the cursor and the seqs above it that were
125
+ * already delivered (no-op for an unknown app or no change).
126
+ *
127
+ * @param appId - App id
128
+ * @param cursor - Safe cursor (before every undelivered change)
129
+ * @param delivered - Delivered seqs above the cursor
130
+ */
131
+ async setProgress(appId, cursor, delivered) {
132
+ const current = (await this.load()).apps[appId];
133
+ if (!current)
134
+ return;
135
+ const sorted = [...delivered].filter((n) => n > cursor).sort((a, b) => a - b);
136
+ const same = current.cursor === cursor && JSON.stringify(current.delivered ?? []) === JSON.stringify(sorted);
137
+ if (same)
138
+ return;
139
+ await this.mutate((d) => {
140
+ const e = d.apps[appId];
141
+ if (!e)
142
+ return;
143
+ e.cursor = cursor;
144
+ if (sorted.length > 0)
145
+ e.delivered = sorted;
146
+ else
147
+ delete e.delivered;
148
+ });
149
+ }
150
+ /**
151
+ * Record a successful wake for the cooldown.
152
+ *
153
+ * @param appId - App id
154
+ * @param recipient - Session or orchestrator key
155
+ * @param at - Epoch ms
156
+ */
157
+ async setLastWake(appId, recipient, at) {
158
+ await this.mutate((d) => {
159
+ const e = d.apps[appId];
160
+ if (e)
161
+ e.wakes = { ...(e.wakes ?? {}), [recipient]: at };
162
+ });
163
+ }
164
+ /**
165
+ * Store the visitor-wake cap state (P3 §3).
166
+ *
167
+ * @param appId - App id
168
+ * @param state - Day, wakes that day, submissions skipped and not yet reported
169
+ */
170
+ async setVisitorWakes(appId, state) {
171
+ await this.mutate((d) => {
172
+ const e = d.apps[appId];
173
+ if (e)
174
+ e.visitorWakes = { day: state.day, count: state.count, skipped: state.skipped };
175
+ });
176
+ }
177
+ /**
178
+ * Mark an app gone from Cloud.
179
+ *
180
+ * @param appId - App id
181
+ */
182
+ async markDeleted(appId) {
183
+ await this.mutate((d) => {
184
+ const e = d.apps[appId];
185
+ if (e) {
186
+ e.deleted = true;
187
+ e.updatedAt = new Date().toISOString();
188
+ }
189
+ });
190
+ }
191
+ }
192
+ //# sourceMappingURL=apps-registry.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps-registry.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/apps/apps-registry.service.ts"],"names":[],"mappings":"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"}