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.
Files changed (46) hide show
  1. package/README.md +64 -109
  2. package/apps/onboarding/bundle.mjs +24 -0
  3. package/apps/onboarding/discovery.mjs +44 -0
  4. package/apps/onboarding/errors.mjs +1 -0
  5. package/apps/onboarding/main.mjs +32 -0
  6. package/apps/onboarding/manager.mjs +532 -0
  7. package/apps/onboarding/server.mjs +56 -0
  8. package/apps/onboarding/web/app.js +154 -0
  9. package/apps/onboarding/web/index.html +15 -0
  10. package/apps/onboarding/web/style.css +3 -0
  11. package/apps/peer/desktop.mjs +8 -6
  12. package/apps/peer/mcp.mjs +1 -1
  13. package/apps/peer/runner.mjs +5 -5
  14. package/apps/peer/runtime.mjs +4 -1
  15. package/apps/peer/wecom.mjs +76 -21
  16. package/bin/codex-collab.mjs +10 -7
  17. package/docs/architecture.md +3 -1
  18. package/docs/desktop-poll.md +16 -8
  19. package/docs/legacy-center.md +109 -0
  20. package/docs/local-automatic-test.md +1 -1
  21. package/docs/local-peer-test.md +1 -1
  22. package/docs/onboarding-audit.md +88 -0
  23. package/docs/onboarding.md +92 -69
  24. package/docs/peer.md +13 -7
  25. package/docs/protocol.md +2 -0
  26. package/docs/team-registry.md +65 -0
  27. package/docs/terminal-onboarding.md +98 -0
  28. package/package.json +6 -3
  29. package/packages/codex-kit/templates/.agents/skills/team-collab-desktop/SKILL.md +3 -3
  30. package/packages/peer/config.mjs +7 -3
  31. package/packages/peer/protocol.mjs +22 -7
  32. package/packages/peer/registry.mjs +133 -0
  33. package/packages/peer/review.mjs +52 -0
  34. package/packages/peer/service.mjs +24 -16
  35. package/packages/peer/store.mjs +59 -7
  36. package/schemas/encrypted-invite.schema.json +42 -0
  37. package/schemas/event.schema.json +51 -0
  38. package/schemas/peer-event.schema.json +44 -0
  39. package/schemas/peer-task.schema.json +21 -0
  40. package/schemas/task.schema.json +18 -0
  41. package/schemas/team-enrollment.schema.json +61 -0
  42. package/schemas/team-invitation.schema.json +108 -0
  43. package/schemas/team-policy.schema.json +182 -0
  44. package/schemas/team-version.schema.json +70 -0
  45. package/scripts/peer/cli.mjs +5 -2
  46. 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
+ }
@@ -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
- task = await service.report(args[0], { type: 'reviewed', decision: args[1] });
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
- const oldExclude = await readFile(excludePath, 'utf8');
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) await writeFile(excludePath, `${oldExclude}${oldExclude.endsWith('\n') || !oldExclude ? '' : '\n'}${addedRules.join('\n')}\n`);
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) await writeFile(excludePath, oldExclude);
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 };