xuym-codex-collab 0.1.1 → 0.3.1
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/README.md +64 -109
- package/apps/onboarding/bundle.mjs +24 -0
- package/apps/onboarding/discovery.mjs +44 -0
- package/apps/onboarding/errors.mjs +1 -0
- package/apps/onboarding/main.mjs +32 -0
- package/apps/onboarding/manager.mjs +532 -0
- package/apps/onboarding/server.mjs +56 -0
- package/apps/onboarding/web/app.js +154 -0
- package/apps/onboarding/web/index.html +15 -0
- package/apps/onboarding/web/style.css +3 -0
- package/apps/peer/desktop.mjs +8 -6
- package/apps/peer/mcp.mjs +1 -1
- package/apps/peer/runner.mjs +5 -5
- package/apps/peer/runtime.mjs +4 -1
- package/apps/peer/wecom.mjs +76 -21
- package/bin/codex-collab.mjs +10 -7
- package/docs/architecture.md +3 -1
- package/docs/desktop-poll.md +16 -8
- package/docs/legacy-center.md +109 -0
- package/docs/local-automatic-test.md +1 -1
- package/docs/local-peer-test.md +1 -1
- package/docs/onboarding-audit.md +88 -0
- package/docs/onboarding.md +92 -69
- package/docs/peer.md +13 -7
- package/docs/protocol.md +2 -0
- package/docs/team-registry.md +65 -0
- package/docs/terminal-onboarding.md +98 -0
- package/package.json +6 -3
- package/packages/codex-kit/templates/.agents/skills/team-collab-desktop/SKILL.md +3 -3
- package/packages/peer/config.mjs +7 -3
- package/packages/peer/protocol.mjs +22 -7
- package/packages/peer/registry.mjs +133 -0
- package/packages/peer/review.mjs +52 -0
- package/packages/peer/service.mjs +24 -16
- package/packages/peer/store.mjs +59 -7
- package/schemas/encrypted-invite.schema.json +42 -0
- package/schemas/event.schema.json +51 -0
- package/schemas/peer-event.schema.json +44 -0
- package/schemas/peer-task.schema.json +21 -0
- package/schemas/task.schema.json +18 -0
- package/schemas/team-enrollment.schema.json +61 -0
- package/schemas/team-invitation.schema.json +108 -0
- package/schemas/team-policy.schema.json +182 -0
- package/schemas/team-version.schema.json +70 -0
- package/scripts/peer/cli.mjs +5 -2
- package/scripts/peer/onboarding.mjs +16 -4
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "urn:codex-collab:team-version:v1",
|
|
4
|
+
"title": "Codex Collab Signed Team Version v1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": [
|
|
8
|
+
"schema_version",
|
|
9
|
+
"version",
|
|
10
|
+
"parent_hash",
|
|
11
|
+
"team_hash",
|
|
12
|
+
"team",
|
|
13
|
+
"actor_id",
|
|
14
|
+
"signature"
|
|
15
|
+
],
|
|
16
|
+
"properties": {
|
|
17
|
+
"schema_version": {
|
|
18
|
+
"const": 1
|
|
19
|
+
},
|
|
20
|
+
"version": {
|
|
21
|
+
"type": "integer",
|
|
22
|
+
"minimum": 1
|
|
23
|
+
},
|
|
24
|
+
"parent_hash": {
|
|
25
|
+
"oneOf": [
|
|
26
|
+
{
|
|
27
|
+
"type": "null"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"type": "string",
|
|
31
|
+
"pattern": "^[a-f0-9]{64}$"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"team_hash": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"pattern": "^[a-f0-9]{64}$"
|
|
38
|
+
},
|
|
39
|
+
"team": {
|
|
40
|
+
"$ref": "urn:codex-collab:team-policy:v2"
|
|
41
|
+
},
|
|
42
|
+
"actor_id": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"pattern": "^[a-zA-Z0-9_-]{1,64}$"
|
|
45
|
+
},
|
|
46
|
+
"enrollment": {
|
|
47
|
+
"type": "object",
|
|
48
|
+
"additionalProperties": false,
|
|
49
|
+
"required": [
|
|
50
|
+
"invite_id",
|
|
51
|
+
"request_id"
|
|
52
|
+
],
|
|
53
|
+
"properties": {
|
|
54
|
+
"invite_id": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$"
|
|
57
|
+
},
|
|
58
|
+
"request_id": {
|
|
59
|
+
"type": "string",
|
|
60
|
+
"pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"signature": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"minLength": 1
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"$comment": "Runtime verifies pinned root hash, contiguous version and parent chain, canonical team_hash, previous-admin signature, immutable existing identities and local anti-rollback checkpoint."
|
|
70
|
+
}
|
package/scripts/peer/cli.mjs
CHANGED
|
@@ -102,8 +102,11 @@ switch (command) {
|
|
|
102
102
|
if (command === 'list') task = await service.list();
|
|
103
103
|
if (command === 'read') task = await service.read(args[0]);
|
|
104
104
|
if (command === 'review') {
|
|
105
|
-
if (!['approved', 'changes_requested'].includes(args[1])) throw new Error('review task-id approved|changes_requested');
|
|
106
|
-
|
|
105
|
+
if (!['approved', 'changes_requested'].includes(args[1])) throw new Error('review task-id approved|changes_requested [R-<seq>] [feedback]');
|
|
106
|
+
const revision = /^R-([1-9][0-9]*)$/.exec(args[2] || '');
|
|
107
|
+
if (args[2]?.startsWith('R-') && (!revision || !Number.isSafeInteger(Number(revision[1])))) throw new Error('invalid review revision; use R-<seq> from the current notification');
|
|
108
|
+
const summary = args.slice(revision ? 3 : 2).join(' ');
|
|
109
|
+
task = await service.report(args[0], { type: 'reviewed', decision: args[1], ...(summary ? { summary } : {}) }, {}, undefined, revision ? Number(revision[1]) : undefined);
|
|
107
110
|
}
|
|
108
111
|
if (command === 'complete') task = await service.report(args[0], { type: 'completed' });
|
|
109
112
|
if (command === 'reopen') task = await service.report(args[0], { type: 'reopened', summary: args.slice(1).join(' ') });
|
|
@@ -44,7 +44,7 @@ export async function readPublicKeyFile(path) {
|
|
|
44
44
|
return key.export({ type: 'spki', format: 'pem' });
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
async function getOrCreateIdentityFiles(agentId, directory) {
|
|
47
|
+
export async function getOrCreateIdentityFiles(agentId, directory) {
|
|
48
48
|
if (!idPattern.test(agentId || '') || !isAbsolute(directory)) throw new Error('provide a valid agent ID and absolute identity directory');
|
|
49
49
|
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
50
50
|
const privatePath = join(directory, `${agentId}.private.json`);
|
|
@@ -187,7 +187,13 @@ export async function attachProject({ configPath, repoPath }) {
|
|
|
187
187
|
const block = `[mcp_servers.${serverName}]\ncommand = ${JSON.stringify(process.execPath)}\nargs = [${JSON.stringify(join(root, 'apps/peer/mcp-main.mjs'))}, ${JSON.stringify(configPath)}]`;
|
|
188
188
|
const next = mergeMcpToml(before, serverName, block);
|
|
189
189
|
const excludePath = await git(repo, 'rev-parse', '--path-format=absolute', '--git-path', 'info/exclude');
|
|
190
|
-
|
|
190
|
+
let oldExclude = '';
|
|
191
|
+
let excludeExisted = true;
|
|
192
|
+
try { oldExclude = await readFile(excludePath, 'utf8'); }
|
|
193
|
+
catch (error) {
|
|
194
|
+
if (error.code !== 'ENOENT') throw error;
|
|
195
|
+
excludeExisted = false;
|
|
196
|
+
}
|
|
191
197
|
const rules = [`/.codex/config.toml`, `/.agents/skills/${skillName}/`, '/.codex-collab-worktrees/'];
|
|
192
198
|
const addedRules = rules.filter((rule) => !oldExclude.split(/\r?\n/).includes(rule));
|
|
193
199
|
const template = await readFile(join(root, `packages/codex-kit/templates/.agents/skills/${skillName}/SKILL.md`), 'utf8');
|
|
@@ -197,12 +203,18 @@ export async function attachProject({ configPath, repoPath }) {
|
|
|
197
203
|
await writeFile(configFile, next, { mode: 0o600 });
|
|
198
204
|
await chmod(configFile, 0o600);
|
|
199
205
|
await writeFile(skillFile, template, { mode: 0o600, flag: 'wx' });
|
|
200
|
-
if (addedRules.length)
|
|
206
|
+
if (addedRules.length) {
|
|
207
|
+
await mkdir(dirname(excludePath), { recursive: true, mode: 0o700 });
|
|
208
|
+
await writeFile(excludePath, `${oldExclude}${oldExclude.endsWith('\n') || !oldExclude ? '' : '\n'}${addedRules.join('\n')}\n`);
|
|
209
|
+
}
|
|
201
210
|
} catch (error) {
|
|
202
211
|
if (before) await writeFile(configFile, before, { mode: 0o600 });
|
|
203
212
|
else await rm(configFile, { force: true });
|
|
204
213
|
await rm(skillDir, { recursive: true, force: true });
|
|
205
|
-
if (addedRules.length)
|
|
214
|
+
if (addedRules.length) {
|
|
215
|
+
if (excludeExisted) await writeFile(excludePath, oldExclude);
|
|
216
|
+
else await rm(excludePath, { force: true });
|
|
217
|
+
}
|
|
206
218
|
throw error;
|
|
207
219
|
}
|
|
208
220
|
return { repo, mcp_config: configFile, skill: skillFile };
|