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.
- package/config/skills/agent/core/app-data/SKILL.md +117 -0
- package/config/skills/agent/core/app-data/execute.sh +141 -0
- package/config/skills/agent/core/app-data/execute.test.sh +108 -0
- package/config/skills/agent/core/publish-app/SKILL.md +248 -0
- package/config/skills/agent/core/publish-app/execute.sh +302 -0
- package/config/skills/agent/core/publish-app/execute.test.sh +205 -0
- package/dist/backend/backend/src/constants.d.ts +115 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +115 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +55 -0
- package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/apps/apps.controller.js +131 -0
- package/dist/backend/backend/src/controllers/apps/apps.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts +53 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.js +108 -0
- package/dist/backend/backend/src/controllers/apps/apps.routes.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +57 -5
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/middleware/body-parser-except.d.ts +25 -0
- package/dist/backend/backend/src/middleware/body-parser-except.d.ts.map +1 -0
- package/dist/backend/backend/src/middleware/body-parser-except.js +33 -0
- package/dist/backend/backend/src/middleware/body-parser-except.js.map +1 -0
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +4 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
- package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/backend/backend/src/services/apps/app-open-link.d.ts +61 -0
- package/dist/backend/backend/src/services/apps/app-open-link.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/app-open-link.js +112 -0
- package/dist/backend/backend/src/services/apps/app-open-link.js.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.d.ts +136 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.js +253 -0
- package/dist/backend/backend/src/services/apps/app-wake-message.js.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake.service.d.ts +145 -0
- package/dist/backend/backend/src/services/apps/app-wake.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/app-wake.service.js +455 -0
- package/dist/backend/backend/src/services/apps/app-wake.service.js.map +1 -0
- package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts +74 -0
- package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/apps-cloud.client.js +120 -0
- package/dist/backend/backend/src/services/apps/apps-cloud.client.js.map +1 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts +125 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.js +192 -0
- package/dist/backend/backend/src/services/apps/apps-registry.service.js.map +1 -0
- package/dist/backend/backend/src/services/apps/apps.service.d.ts +466 -0
- package/dist/backend/backend/src/services/apps/apps.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/apps.service.js +740 -0
- package/dist/backend/backend/src/services/apps/apps.service.js.map +1 -0
- package/dist/backend/backend/src/services/apps/apps.wiring.d.ts +97 -0
- package/dist/backend/backend/src/services/apps/apps.wiring.d.ts.map +1 -0
- package/dist/backend/backend/src/services/apps/apps.wiring.js +153 -0
- package/dist/backend/backend/src/services/apps/apps.wiring.js.map +1 -0
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +3 -1
- package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/logger.service.d.ts +5 -0
- package/dist/backend/backend/src/services/core/logger.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/logger.service.js +8 -0
- package/dist/backend/backend/src/services/core/logger.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.js +3 -1
- package/dist/backend/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +115 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +115 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +5 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
- package/dist/cli/backend/src/services/apps/app-open-link.d.ts +61 -0
- package/dist/cli/backend/src/services/apps/app-open-link.d.ts.map +1 -0
- package/dist/cli/backend/src/services/apps/app-open-link.js +112 -0
- package/dist/cli/backend/src/services/apps/app-open-link.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +3 -1
- package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
- package/dist/cli/backend/src/services/core/logger.service.d.ts +5 -0
- package/dist/cli/backend/src/services/core/logger.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/logger.service.js +8 -0
- package/dist/cli/backend/src/services/core/logger.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.js +3 -1
- package/dist/cli/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
- 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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"}
|