@wenrwa/marketplace-cli 0.8.14 → 0.8.15
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/dist/__tests__/bridge-linked-repos-pointer.test.d.ts +1 -0
- package/dist/__tests__/bridge-linked-repos-pointer.test.js +44 -0
- package/dist/bridge/contextWriter.d.ts +7 -0
- package/dist/bridge/contextWriter.js +3 -0
- package/dist/bridge/linkedRepos.d.ts +4 -0
- package/dist/bridge/linkedRepos.js +5 -0
- package/dist/bridge/relayClient.d.ts +1 -0
- package/dist/bridge/relayClient.js +2 -0
- package/dist/bridge/workGraphPointer.d.ts +13 -0
- package/dist/bridge/workGraphPointer.js +16 -0
- package/dist/commands/bridge.js +14 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* lr-03 — the managed region tells an agent which linked repos it has, where
|
|
5
|
+
* they are on the box, and whether it may push to each. Without this an agent
|
|
6
|
+
* never learns the backend sits at /data/linked/<ws>/backend.
|
|
7
|
+
*/
|
|
8
|
+
const contextWriter_1 = require("../bridge/contextWriter");
|
|
9
|
+
const workGraphPointer_1 = require("../bridge/workGraphPointer");
|
|
10
|
+
const WS = '11111111-1111-4111-8111-111111111111';
|
|
11
|
+
const LINKED = [
|
|
12
|
+
{ alias: 'backend', fullName: 'acme/backend', writable: true, path: `/data/linked/${WS}/backend` },
|
|
13
|
+
{ alias: 'cli', fullName: 'acme/cli', writable: false, path: `/data/linked/${WS}/cli` },
|
|
14
|
+
];
|
|
15
|
+
describe('linkedReposSection', () => {
|
|
16
|
+
it('one line per repo: alias, repo, path, and whether pushing is allowed', () => {
|
|
17
|
+
expect((0, workGraphPointer_1.linkedReposSection)({ linkedRepos: LINKED })).toBe([
|
|
18
|
+
'## Linked repos',
|
|
19
|
+
'This workspace also has these repos, each its own checkout:',
|
|
20
|
+
`- \`backend\` (acme/backend) at /data/linked/${WS}/backend — you can push`,
|
|
21
|
+
`- \`cli\` (acme/cli) at /data/linked/${WS}/cli — read-only, pushes are refused`,
|
|
22
|
+
].join('\n'));
|
|
23
|
+
});
|
|
24
|
+
it('nothing linked → no section', () => {
|
|
25
|
+
expect((0, workGraphPointer_1.linkedReposSection)({ linkedRepos: [] })).toBeNull();
|
|
26
|
+
expect((0, workGraphPointer_1.linkedReposSection)({})).toBeNull();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('writeContext carries it inside the pointer block', () => {
|
|
30
|
+
it('a pointers-only refresh writes the section between the pointer markers', () => {
|
|
31
|
+
const files = new Map();
|
|
32
|
+
(0, contextWriter_1.writeContext)({ workspaceId: WS, pointersOnly: true, linkedRepos: LINKED }, {
|
|
33
|
+
reposBaseDir: '/data/repos',
|
|
34
|
+
exists: (p) => files.has(p),
|
|
35
|
+
readFile: (p) => files.get(p) ?? '',
|
|
36
|
+
writeFile: (p, c) => { files.set(p, c); },
|
|
37
|
+
mkdirp: () => { },
|
|
38
|
+
});
|
|
39
|
+
const written = [...files.values()].join('\n');
|
|
40
|
+
const block = written.slice(written.indexOf(contextWriter_1.POINTERS_START_MARKER), written.indexOf(contextWriter_1.POINTERS_END_MARKER));
|
|
41
|
+
expect(block).toContain('## Linked repos');
|
|
42
|
+
expect(block).toContain(`/data/linked/${WS}/cli — read-only`);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -35,6 +35,13 @@ export declare function writeContext(input: {
|
|
|
35
35
|
/** Absent only for a pointers-only refresh (wmr-07). */
|
|
36
36
|
content?: string;
|
|
37
37
|
workGraphAvailable?: boolean;
|
|
38
|
+
/** lr-03 — this workspace's linked repos on the box (linkedReposSection). */
|
|
39
|
+
linkedRepos?: Array<{
|
|
40
|
+
alias: string;
|
|
41
|
+
fullName: string;
|
|
42
|
+
writable: boolean;
|
|
43
|
+
path: string;
|
|
44
|
+
}>;
|
|
38
45
|
/** 2026-10-02 — a match workspace: MATCH_POINTER replaces the work-queue pointer (workSection). */
|
|
39
46
|
match?: boolean;
|
|
40
47
|
/**
|
|
@@ -173,6 +173,9 @@ function writeContextFile(input, claudeMdPath, seedPath, workspaceRoot, deps) {
|
|
|
173
173
|
pointers.push(work);
|
|
174
174
|
if (input.memoryAvailable)
|
|
175
175
|
pointers.push((0, memoryPointer_1.memorySection)(input.memoryBrief));
|
|
176
|
+
const linked = (0, workGraphPointer_1.linkedReposSection)(input);
|
|
177
|
+
if (linked)
|
|
178
|
+
pointers.push(linked);
|
|
176
179
|
const browser = (0, workGraphPointer_1.browserSection)(input);
|
|
177
180
|
if (browser)
|
|
178
181
|
pointers.push(browser);
|
|
@@ -3,7 +3,11 @@ export interface LinkedRepoRef {
|
|
|
3
3
|
alias: string;
|
|
4
4
|
fullName: string;
|
|
5
5
|
cloneUrl: string;
|
|
6
|
+
/** Shown to the agent (context pointer); GitHub enforces it via the token. */
|
|
7
|
+
writable?: boolean;
|
|
6
8
|
}
|
|
9
|
+
/** /data/linked/<workspaceId>/<alias> — the ONE place a linked clone lives. */
|
|
10
|
+
export declare function linkedRepoPath(linkedBaseDir: string, workspaceId: string, alias: string): string;
|
|
7
11
|
export interface LinkedRepoResult {
|
|
8
12
|
alias: string;
|
|
9
13
|
action: 'existing' | 'cloned' | 'failed';
|
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.linkedRepoPath = linkedRepoPath;
|
|
6
7
|
exports.ensureLinkedRepos = ensureLinkedRepos;
|
|
7
8
|
/**
|
|
8
9
|
* lr-03 — clone a workspace's LINKED repos on the box
|
|
@@ -22,6 +23,10 @@ exports.ensureLinkedRepos = ensureLinkedRepos;
|
|
|
22
23
|
* - Never throws: a failed clone must not break the terminal that opened.
|
|
23
24
|
*/
|
|
24
25
|
const path_1 = __importDefault(require("path"));
|
|
26
|
+
/** /data/linked/<workspaceId>/<alias> — the ONE place a linked clone lives. */
|
|
27
|
+
function linkedRepoPath(linkedBaseDir, workspaceId, alias) {
|
|
28
|
+
return path_1.default.join(linkedBaseDir, workspaceId, alias);
|
|
29
|
+
}
|
|
25
30
|
const ALIAS = /^[a-z0-9][a-z0-9-]{0,31}$/;
|
|
26
31
|
const WORKSPACE_ID = /^[A-Za-z0-9-]{1,64}$/;
|
|
27
32
|
const FULL_NAME = /^[A-Za-z0-9._-]{1,100}\/[A-Za-z0-9._-]{1,100}$/;
|
|
@@ -1231,6 +1231,8 @@ function startRelayClient(opts) {
|
|
|
1231
1231
|
if (workspaceId && opts.refreshContextPointers) {
|
|
1232
1232
|
void Promise.resolve(opts.refreshContextPointers({
|
|
1233
1233
|
workspaceId,
|
|
1234
|
+
// lr-03: absent on the frame = none linked (or an older relay).
|
|
1235
|
+
linkedRepos: Array.isArray(linkedRepos) ? linkedRepos : [],
|
|
1234
1236
|
// oc-23: the relay-injected env names the agent's engine; absent = Claude.
|
|
1235
1237
|
...(injectedEnv?.WENRWA_AGENT_ENGINE ? { engine: injectedEnv.WENRWA_AGENT_ENGINE } : {}),
|
|
1236
1238
|
})).catch((err) => {
|
|
@@ -51,6 +51,19 @@ export declare function workSection(input: {
|
|
|
51
51
|
workGraphAvailable?: boolean;
|
|
52
52
|
match?: boolean;
|
|
53
53
|
}): string | null;
|
|
54
|
+
/**
|
|
55
|
+
* lr-03 — which linked repos this workspace has, where each is on the box, and
|
|
56
|
+
* whether the agent may push there (a read-only link's token is contents:read,
|
|
57
|
+
* so a push is refused by GitHub). Silent when nothing is linked.
|
|
58
|
+
*/
|
|
59
|
+
export declare function linkedReposSection(input: {
|
|
60
|
+
linkedRepos?: Array<{
|
|
61
|
+
alias: string;
|
|
62
|
+
fullName: string;
|
|
63
|
+
writable: boolean;
|
|
64
|
+
path: string;
|
|
65
|
+
}>;
|
|
66
|
+
}): string | null;
|
|
54
67
|
/**
|
|
55
68
|
* cvt-09 (amended by the 2026-10-04 show-in-browser-tabs change) — tells the
|
|
56
69
|
* agent its pilot watches a Browser pane and WHEN to call `show_in_browser`:
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SECRETS_POINTER = exports.KEYS_POINTER = exports.BROWSER_POINTER = exports.MATCH_POINTER = exports.WORK_GRAPH_POINTER = void 0;
|
|
4
4
|
exports.workSection = workSection;
|
|
5
|
+
exports.linkedReposSection = linkedReposSection;
|
|
5
6
|
exports.browserSection = browserSection;
|
|
6
7
|
exports.keysSection = keysSection;
|
|
7
8
|
exports.withSecretsSection = withSecretsSection;
|
|
@@ -67,6 +68,21 @@ function workSection(input) {
|
|
|
67
68
|
return exports.MATCH_POINTER;
|
|
68
69
|
return input.workGraphAvailable ? exports.WORK_GRAPH_POINTER : null;
|
|
69
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* lr-03 — which linked repos this workspace has, where each is on the box, and
|
|
73
|
+
* whether the agent may push there (a read-only link's token is contents:read,
|
|
74
|
+
* so a push is refused by GitHub). Silent when nothing is linked.
|
|
75
|
+
*/
|
|
76
|
+
function linkedReposSection(input) {
|
|
77
|
+
const repos = input.linkedRepos ?? [];
|
|
78
|
+
if (repos.length === 0)
|
|
79
|
+
return null;
|
|
80
|
+
return [
|
|
81
|
+
'## Linked repos',
|
|
82
|
+
'This workspace also has these repos, each its own checkout:',
|
|
83
|
+
...repos.map((r) => `- \`${r.alias}\` (${r.fullName}) at ${r.path} — ${r.writable ? 'you can push' : 'read-only, pushes are refused'}`),
|
|
84
|
+
].join('\n');
|
|
85
|
+
}
|
|
70
86
|
/**
|
|
71
87
|
* cvt-09 (amended by the 2026-10-04 show-in-browser-tabs change) — tells the
|
|
72
88
|
* agent its pilot watches a Browser pane and WHEN to call `show_in_browser`:
|
package/dist/commands/bridge.js
CHANGED
|
@@ -700,6 +700,15 @@ exports.bridgeCommand = new commander_1.Command('bridge')
|
|
|
700
700
|
// lr-03 — a workspace's linked repos, cloned beside (never inside)
|
|
701
701
|
// /data/repos, each with its own credential from the broker.
|
|
702
702
|
const linkedBaseDir = process.env.WENRWA_LINKED_DIR || path.join(path.dirname(reposBaseDir), 'linked');
|
|
703
|
+
// The latest list each workspace's open frame carried — so a file-selection
|
|
704
|
+
// write (which has no frame of its own) keeps the agent's linked-repo lines.
|
|
705
|
+
const linkedReposByWorkspace = new Map();
|
|
706
|
+
const linkedPointerFor = (workspaceId) => (linkedReposByWorkspace.get(workspaceId) ?? []).map((r) => ({
|
|
707
|
+
alias: r.alias,
|
|
708
|
+
fullName: r.fullName,
|
|
709
|
+
writable: r.writable === true,
|
|
710
|
+
path: (0, linkedRepos_1.linkedRepoPath)(linkedBaseDir, workspaceId, r.alias),
|
|
711
|
+
}));
|
|
703
712
|
const ensureLinked = (args) => (0, linkedRepos_1.ensureLinkedRepos)(args, {
|
|
704
713
|
linkedBaseDir,
|
|
705
714
|
credentialFor: (workspaceId, fullName) => gitTokenBroker.get(workspaceId, fullName),
|
|
@@ -911,7 +920,9 @@ exports.bridgeCommand = new commander_1.Command('bridge')
|
|
|
911
920
|
only sends one when the pilot has files selected, so most workspaces
|
|
912
921
|
never got the pointers at all.
|
|
913
922
|
*/
|
|
914
|
-
refreshContextPointers: async ({ workspaceId, engine }) => {
|
|
923
|
+
refreshContextPointers: async ({ workspaceId, engine, linkedRepos }) => {
|
|
924
|
+
if (linkedRepos)
|
|
925
|
+
linkedReposByWorkspace.set(workspaceId, linkedRepos);
|
|
915
926
|
const memoryAvailable = Boolean(process.env.WENRWA_CONNECT_TOKEN);
|
|
916
927
|
// 2026-10-02 — the same reply says whether this is a MATCH workspace.
|
|
917
928
|
const briefInfo = memoryAvailable ? await (0, memoryBrief_1.fetchWorkspaceBrief)(workspaceId) : null;
|
|
@@ -920,6 +931,7 @@ exports.bridgeCommand = new commander_1.Command('bridge')
|
|
|
920
931
|
workspaceId,
|
|
921
932
|
pointersOnly: true,
|
|
922
933
|
engine,
|
|
934
|
+
linkedRepos: linkedPointerFor(workspaceId),
|
|
923
935
|
workGraphAvailable: Boolean(process.env.WENRWA_CONNECT_TOKEN),
|
|
924
936
|
memoryAvailable,
|
|
925
937
|
memoryBrief,
|
|
@@ -949,6 +961,7 @@ exports.bridgeCommand = new commander_1.Command('bridge')
|
|
|
949
961
|
workspaceId,
|
|
950
962
|
content,
|
|
951
963
|
engine,
|
|
964
|
+
linkedRepos: linkedPointerFor(workspaceId),
|
|
952
965
|
// wgcp-01 — same gate as checkStorageQuota above: WENRWA_CONNECT_TOKEN
|
|
953
966
|
// is only injected at container boot when this workspace actually has
|
|
954
967
|
// MCP world-wiring (hosted-container.service.ts's machineEnv). Absent
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wenrwa/marketplace-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.15",
|
|
4
4
|
"description": "CLI tool for the Wenrwa Agent Marketplace — monitor bounties, agents, workspaces, and treasury from your terminal",
|
|
5
5
|
"author": "Wenrwa <dev@wenrwa.com>",
|
|
6
6
|
"license": "MIT",
|