sinapse-ai 7.7.3 → 7.7.5
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/.codex/catalog.json +157 -0
- package/.codex/command-registry.json +441 -0
- package/.codex/delegation-matrix.json +512 -0
- package/.codex/handoff-packet.schema.json +148 -0
- package/.codex/scripts/generate-codex-greeting.js +101 -0
- package/.codex/scripts/resolve-codex-command.js +147 -0
- package/.codex/scripts/resolve-codex-delegation.js +205 -0
- package/.codex/skills/sinapse-analyst/SKILL.md +5 -4
- package/.codex/skills/sinapse-architect/SKILL.md +5 -4
- package/.codex/skills/sinapse-data-engineer/SKILL.md +5 -4
- package/.codex/skills/sinapse-dev/SKILL.md +5 -4
- package/.codex/skills/sinapse-devops/SKILL.md +5 -4
- package/.codex/skills/sinapse-orqx/SKILL.md +10 -15
- package/.codex/skills/sinapse-pm/SKILL.md +5 -4
- package/.codex/skills/sinapse-po/SKILL.md +4 -3
- package/.codex/skills/sinapse-qa/SKILL.md +12 -11
- package/.codex/skills/sinapse-sm/SKILL.md +5 -4
- package/.codex/skills/sinapse-squad-creator/SKILL.md +5 -4
- package/.codex/skills/sinapse-ux-design-expert/SKILL.md +5 -4
- package/.codex/tasks/convene-sinapse-council.md +28 -0
- package/.codex/tasks/create-sinapse-strategic-brief.md +29 -0
- package/.codex/tasks/onboard-sinapse-codex.md +34 -0
- package/.codex/tasks/plan-sinapse-initiative.md +33 -0
- package/.codex/tasks/resolve-sinapse-conflict.md +28 -0
- package/.codex/tasks/route-sinapse-request.md +35 -0
- package/.codex/tasks/status-sinapse-capabilities.md +28 -0
- package/.sinapse-ai/core-config.yaml +1 -1
- package/.sinapse-ai/data/entity-registry.yaml +874 -749
- package/.sinapse-ai/data/registry-update-log.jsonl +13 -0
- package/.sinapse-ai/infrastructure/scripts/codex-parity/catalog.js +123 -0
- package/.sinapse-ai/infrastructure/scripts/codex-skills-sync/index.js +60 -11
- package/.sinapse-ai/infrastructure/scripts/codex-skills-sync/validate.js +44 -16
- package/.sinapse-ai/infrastructure/scripts/sync-codex-local-first.js +156 -0
- package/.sinapse-ai/infrastructure/scripts/validate-codex-command-registry.js +264 -0
- package/.sinapse-ai/infrastructure/scripts/validate-codex-delegation.js +292 -0
- package/.sinapse-ai/infrastructure/scripts/validate-codex-integration.js +15 -6
- package/.sinapse-ai/infrastructure/scripts/validate-codex-sync.js +159 -0
- package/.sinapse-ai/infrastructure/scripts/validate-parity.js +3 -1
- package/.sinapse-ai/infrastructure/scripts/validate-paths.js +8 -10
- package/.sinapse-ai/infrastructure/templates/safe-collab/README.md +8 -0
- package/.sinapse-ai/install-manifest.yaml +39 -19
- package/.sinapse-ai/project-config.yaml +1 -1
- package/bin/utils/collab-start.js +267 -0
- package/bin/utils/git-branch-guard.js +76 -0
- package/bin/utils/pre-push-safety.js +110 -0
- package/bin/utils/staged-secret-scan.js +108 -0
- package/docs/codex-parity-program.md +670 -0
- package/docs/codex-total-parity-orchestration-plan.md +301 -0
- package/docs/codex-workflow-task-parity.md +87 -0
- package/docs/collaboration-autonomy-plan.md +243 -0
- package/docs/guides/framework-contributor-mode.md +310 -0
- package/docs/guides/parallel-collaboration-source-of-truth.md +481 -0
- package/package.json +14 -3
- package/packages/installer/tests/unit/artifact-copy-pipeline/artifact-copy-pipeline.test.js +7 -2
- package/packages/installer/tests/unit/entity-registry-bootstrap.test.js +2 -2
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { spawnSync } = require('child_process');
|
|
7
|
+
const { loadCodexCatalogConfig } = require('./codex-parity/catalog');
|
|
8
|
+
const { validateCodexCommandRegistry } = require('./validate-codex-command-registry');
|
|
9
|
+
const { validateCodexDelegation } = require('./validate-codex-delegation');
|
|
10
|
+
const { validateCodexIntegration } = require('./validate-codex-integration');
|
|
11
|
+
const { validateCodexSkills } = require('./codex-skills-sync/validate');
|
|
12
|
+
const { validatePaths } = require('./validate-paths');
|
|
13
|
+
|
|
14
|
+
function parseArgs(argv = process.argv.slice(2)) {
|
|
15
|
+
const args = new Set(argv);
|
|
16
|
+
return {
|
|
17
|
+
quiet: args.has('--quiet') || args.has('-q'),
|
|
18
|
+
json: args.has('--json'),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function runLegacyCodexValidate(projectRoot, options = {}) {
|
|
23
|
+
const args = [
|
|
24
|
+
path.join('.sinapse-ai', 'infrastructure', 'scripts', 'ide-sync', 'index.js'),
|
|
25
|
+
'validate',
|
|
26
|
+
'--ide',
|
|
27
|
+
'codex',
|
|
28
|
+
'--strict',
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
if (options.quiet) args.push('--quiet');
|
|
32
|
+
|
|
33
|
+
const result = spawnSync(process.execPath, args, {
|
|
34
|
+
cwd: projectRoot,
|
|
35
|
+
encoding: 'utf8',
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
ok: result.status === 0,
|
|
40
|
+
mode: 'canonical',
|
|
41
|
+
checks: [],
|
|
42
|
+
errors: result.status === 0 ? [] : ['Legacy Codex sync validation failed'],
|
|
43
|
+
warnings: [],
|
|
44
|
+
raw: [result.stdout, result.stderr].filter(Boolean).join('\n').trim(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function normalizeCheck(id, input) {
|
|
49
|
+
return {
|
|
50
|
+
id,
|
|
51
|
+
ok: Boolean(input?.ok),
|
|
52
|
+
errors: Array.isArray(input?.errors) ? input.errors : [],
|
|
53
|
+
warnings: Array.isArray(input?.warnings) ? input.warnings : [],
|
|
54
|
+
metrics: input?.metrics || {},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function validateCodexSync(options = {}, deps = {}) {
|
|
59
|
+
const projectRoot = options.projectRoot || process.cwd();
|
|
60
|
+
const config = loadCodexCatalogConfig(projectRoot);
|
|
61
|
+
const runLegacyValidate = deps.runLegacyCodexValidate || runLegacyCodexValidate;
|
|
62
|
+
const runCodexCommands = deps.validateCodexCommandRegistry || validateCodexCommandRegistry;
|
|
63
|
+
const runCodexDelegation = deps.validateCodexDelegation || validateCodexDelegation;
|
|
64
|
+
const runCodexIntegration = deps.validateCodexIntegration || validateCodexIntegration;
|
|
65
|
+
const runCodexSkills = deps.validateCodexSkills || validateCodexSkills;
|
|
66
|
+
const runPaths = deps.validatePaths || validatePaths;
|
|
67
|
+
|
|
68
|
+
if (config.catalogMode !== 'expanded') {
|
|
69
|
+
return runLegacyValidate(projectRoot, options);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const catalogPath = path.join(projectRoot, '.codex', 'catalog.json');
|
|
73
|
+
const checks = [
|
|
74
|
+
normalizeCheck('codex-integration', runCodexIntegration({ projectRoot, quiet: true })),
|
|
75
|
+
normalizeCheck('codex-commands', runCodexCommands({ projectRoot, quiet: true })),
|
|
76
|
+
normalizeCheck('codex-delegation', runCodexDelegation({ projectRoot, quiet: true })),
|
|
77
|
+
normalizeCheck('codex-skills', runCodexSkills({ projectRoot, strict: true, quiet: true })),
|
|
78
|
+
normalizeCheck('paths', runPaths({ projectRoot, quiet: true })),
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
if (!fs.existsSync(catalogPath)) {
|
|
82
|
+
checks.unshift({
|
|
83
|
+
id: 'codex-catalog',
|
|
84
|
+
ok: false,
|
|
85
|
+
errors: ['Missing Codex catalog file: .codex/catalog.json'],
|
|
86
|
+
warnings: [],
|
|
87
|
+
metrics: {},
|
|
88
|
+
});
|
|
89
|
+
} else {
|
|
90
|
+
checks.unshift({
|
|
91
|
+
id: 'codex-catalog',
|
|
92
|
+
ok: true,
|
|
93
|
+
errors: [],
|
|
94
|
+
warnings: [],
|
|
95
|
+
metrics: {},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
ok: checks.every((check) => check.ok),
|
|
101
|
+
mode: 'expanded',
|
|
102
|
+
checks,
|
|
103
|
+
errors: checks.flatMap((check) => check.errors.map((error) => `${check.id}: ${error}`)),
|
|
104
|
+
warnings: checks.flatMap((check) => check.warnings.map((warning) => `${check.id}: ${warning}`)),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function formatHumanReport(result) {
|
|
109
|
+
if (result.mode === 'canonical' && result.raw) {
|
|
110
|
+
return result.raw;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const lines = [
|
|
114
|
+
result.ok
|
|
115
|
+
? 'OK Codex sync validation passed'
|
|
116
|
+
: `X Codex sync validation failed (${result.errors.length} issue(s))`,
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
for (const check of result.checks || []) {
|
|
120
|
+
lines.push(`${check.ok ? 'OK' : 'X'} ${check.id}`);
|
|
121
|
+
if (check.errors.length > 0) {
|
|
122
|
+
lines.push(...check.errors.map((error) => `- ${error}`));
|
|
123
|
+
}
|
|
124
|
+
if (check.warnings.length > 0) {
|
|
125
|
+
lines.push(...check.warnings.map((warning) => `! ${warning}`));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return lines.join('\n');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function main() {
|
|
133
|
+
const args = parseArgs();
|
|
134
|
+
const result = validateCodexSync(args);
|
|
135
|
+
|
|
136
|
+
if (!args.quiet) {
|
|
137
|
+
if (args.json) {
|
|
138
|
+
console.log(JSON.stringify(result, null, 2));
|
|
139
|
+
} else {
|
|
140
|
+
console.log(formatHumanReport(result));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!result.ok) {
|
|
145
|
+
process.exitCode = 1;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (require.main === module) {
|
|
150
|
+
main();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = {
|
|
154
|
+
parseArgs,
|
|
155
|
+
validateCodexSync,
|
|
156
|
+
formatHumanReport,
|
|
157
|
+
runLegacyCodexValidate,
|
|
158
|
+
normalizeCheck,
|
|
159
|
+
};
|
|
@@ -6,6 +6,7 @@ const path = require('path');
|
|
|
6
6
|
const yaml = require('js-yaml');
|
|
7
7
|
const { spawnSync } = require('child_process');
|
|
8
8
|
const { validateClaudeIntegration } = require('./validate-claude-integration');
|
|
9
|
+
const { validateCodexSync } = require('./validate-codex-sync');
|
|
9
10
|
const { validateCodexIntegration } = require('./validate-codex-integration');
|
|
10
11
|
const { validateCodexSkills } = require('./codex-skills-sync/validate');
|
|
11
12
|
const { validatePaths } = require('./validate-paths');
|
|
@@ -218,6 +219,7 @@ function diffCompatibilityContracts(currentContract, previousContract) {
|
|
|
218
219
|
function runParityValidation(options = {}, deps = {}) {
|
|
219
220
|
const projectRoot = options.projectRoot || process.cwd();
|
|
220
221
|
const runSync = deps.runSyncValidate || runSyncValidate;
|
|
222
|
+
const runCodexSync = deps.validateCodexSync || validateCodexSync;
|
|
221
223
|
const runClaudeIntegration = deps.validateClaudeIntegration || validateClaudeIntegration;
|
|
222
224
|
const runCodexIntegration = deps.validateCodexIntegration || validateCodexIntegration;
|
|
223
225
|
const runCodexSkills = deps.validateCodexSkills || validateCodexSkills;
|
|
@@ -234,7 +236,7 @@ function runParityValidation(options = {}, deps = {}) {
|
|
|
234
236
|
const checks = [
|
|
235
237
|
{ id: 'claude-sync', exec: () => runSync('claude-code', projectRoot) },
|
|
236
238
|
{ id: 'claude-integration', exec: () => runClaudeIntegration({ projectRoot }) },
|
|
237
|
-
{ id: 'codex-sync', exec: () =>
|
|
239
|
+
{ id: 'codex-sync', exec: () => runCodexSync({ projectRoot, quiet: true }) },
|
|
238
240
|
{ id: 'codex-integration', exec: () => runCodexIntegration({ projectRoot }) },
|
|
239
241
|
{ id: 'codex-skills', exec: () => runCodexSkills({ projectRoot, strict: true, quiet: true }) },
|
|
240
242
|
{ id: 'paths', exec: () => runPaths({ projectRoot }) },
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const {
|
|
7
|
+
loadCodexCatalogConfig,
|
|
8
|
+
validateSkillActivationPaths,
|
|
9
|
+
} = require('./codex-parity/catalog');
|
|
6
10
|
|
|
7
11
|
const FORBIDDEN_ABSOLUTE_PATTERNS = [
|
|
8
12
|
/\/Users\/[^\s/'"]+/g,
|
|
@@ -54,21 +58,15 @@ function collectAbsolutePathViolations(content, filePath) {
|
|
|
54
58
|
return errors;
|
|
55
59
|
}
|
|
56
60
|
|
|
57
|
-
function validateSkillPathConventions(content, filePath) {
|
|
58
|
-
|
|
59
|
-
if (!content.includes('.sinapse-ai/development/agents/')) {
|
|
60
|
-
errors.push(`${filePath} missing canonical source path ".sinapse-ai/development/agents/"`);
|
|
61
|
-
}
|
|
62
|
-
if (!content.includes('.sinapse-ai/development/scripts/generate-greeting.js')) {
|
|
63
|
-
errors.push(`${filePath} missing canonical greeting script path`);
|
|
64
|
-
}
|
|
65
|
-
return errors;
|
|
61
|
+
function validateSkillPathConventions(content, filePath, config) {
|
|
62
|
+
return validateSkillActivationPaths(content, filePath, config);
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
function validatePaths(options = {}) {
|
|
69
66
|
const resolved = { ...getDefaultOptions(), ...options };
|
|
70
67
|
const errors = [];
|
|
71
68
|
const checkedFiles = [];
|
|
69
|
+
const config = loadCodexCatalogConfig(resolved.projectRoot);
|
|
72
70
|
|
|
73
71
|
const skillFiles = listSkillFiles(resolved.skillsDir);
|
|
74
72
|
const filesToCheck = [...resolved.requiredFiles, ...skillFiles];
|
|
@@ -90,7 +88,7 @@ function validatePaths(options = {}) {
|
|
|
90
88
|
errors.push(...collectAbsolutePathViolations(content, path.relative(resolved.projectRoot, file)));
|
|
91
89
|
|
|
92
90
|
if (file.endsWith('SKILL.md')) {
|
|
93
|
-
errors.push(...validateSkillPathConventions(content, path.relative(resolved.projectRoot, file)));
|
|
91
|
+
errors.push(...validateSkillPathConventions(content, path.relative(resolved.projectRoot, file), config));
|
|
94
92
|
}
|
|
95
93
|
}
|
|
96
94
|
|
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
Template reutilizavel para configurar colaboracao segura em qualquer projeto.
|
|
4
4
|
|
|
5
|
+
## Fonte canonica
|
|
6
|
+
|
|
7
|
+
Para a politica completa e atualizada de colaboracao paralela, use:
|
|
8
|
+
|
|
9
|
+
- `docs/guides/parallel-collaboration-source-of-truth.md`
|
|
10
|
+
|
|
11
|
+
Este README explica o template. O documento acima define a regra mestra.
|
|
12
|
+
|
|
5
13
|
## Uso rapido
|
|
6
14
|
|
|
7
15
|
```bash
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
# - SHA256 hashes for change detection
|
|
8
8
|
# - File types for categorization
|
|
9
9
|
#
|
|
10
|
-
version: 7.7.
|
|
11
|
-
generated_at: "2026-04-
|
|
10
|
+
version: 7.7.5
|
|
11
|
+
generated_at: "2026-04-03T00:28:11.575Z"
|
|
12
12
|
generator: scripts/generate-install-manifest.js
|
|
13
|
-
file_count:
|
|
13
|
+
file_count: 1118
|
|
14
14
|
files:
|
|
15
15
|
- path: cli/commands/config/index.js
|
|
16
16
|
hash: sha256:66f111eceef0f60fa0a8904add783b615d55b01d5fe36408623c3dd828e702f6
|
|
@@ -189,9 +189,9 @@ files:
|
|
|
189
189
|
type: cli
|
|
190
190
|
size: 5907
|
|
191
191
|
- path: core-config.yaml
|
|
192
|
-
hash: sha256:
|
|
192
|
+
hash: sha256:fc24a8286b20ec2558c90186e99124b96d26b287ff107b747c2b68b1102e0cc8
|
|
193
193
|
type: config
|
|
194
|
-
size:
|
|
194
|
+
size: 10513
|
|
195
195
|
- path: core/code-intel/code-intel-client.js
|
|
196
196
|
hash: sha256:6c9a08a37775acf90397aa079a4ad2c5edcc47f2cfd592b26ae9f3d154d1deb8
|
|
197
197
|
type: core
|
|
@@ -1237,9 +1237,9 @@ files:
|
|
|
1237
1237
|
type: data
|
|
1238
1238
|
size: 9586
|
|
1239
1239
|
- path: data/entity-registry.yaml
|
|
1240
|
-
hash: sha256:
|
|
1240
|
+
hash: sha256:e3e57f3070134b76851762a0666b665228f061d3ff37ee513e7b6ae5dcef3b62
|
|
1241
1241
|
type: data
|
|
1242
|
-
size:
|
|
1242
|
+
size: 515807
|
|
1243
1243
|
- path: data/learned-patterns.yaml
|
|
1244
1244
|
hash: sha256:24ac0b160615583a0ff783d3da8af80b7f94191575d6db2054ec8e10a3f945dc
|
|
1245
1245
|
type: data
|
|
@@ -3052,14 +3052,18 @@ files:
|
|
|
3052
3052
|
hash: sha256:47b3f9044ce9b92b8c486a75da82afc4cc6b49d5d97e722ef5a1938fbf49943a
|
|
3053
3053
|
type: script
|
|
3054
3054
|
size: 40744
|
|
3055
|
+
- path: infrastructure/scripts/codex-parity/catalog.js
|
|
3056
|
+
hash: sha256:cfef97860788a119c44cbb18b4249ad538814f99a03b2ca13e66dd74aa8b5242
|
|
3057
|
+
type: script
|
|
3058
|
+
size: 3527
|
|
3055
3059
|
- path: infrastructure/scripts/codex-skills-sync/index.js
|
|
3056
|
-
hash: sha256:
|
|
3060
|
+
hash: sha256:9eb2637a4f1f6edeabf358734b14e4c709bed37560f2e40aebf1ea3ef4572c3c
|
|
3057
3061
|
type: script
|
|
3058
|
-
size:
|
|
3062
|
+
size: 7494
|
|
3059
3063
|
- path: infrastructure/scripts/codex-skills-sync/validate.js
|
|
3060
|
-
hash: sha256:
|
|
3064
|
+
hash: sha256:1a1301d2e3f558bedf3a1ab2c5c9ee2868a4c253068311d5014987917f367443
|
|
3061
3065
|
type: script
|
|
3062
|
-
size:
|
|
3066
|
+
size: 5626
|
|
3063
3067
|
- path: infrastructure/scripts/collect-tool-usage.js
|
|
3064
3068
|
hash: sha256:510b621078602273fb146eef57d115b08988ea43d03eb5d92192050c13e95efe
|
|
3065
3069
|
type: script
|
|
@@ -3372,6 +3376,10 @@ files:
|
|
|
3372
3376
|
hash: sha256:ceb0450fa12fa48f0255bb4565858eb1a97b28c30b98d36cb61d52d72e08b054
|
|
3373
3377
|
type: script
|
|
3374
3378
|
size: 22394
|
|
3379
|
+
- path: infrastructure/scripts/sync-codex-local-first.js
|
|
3380
|
+
hash: sha256:ad5245ead7243a39cd5116f44fcf1234ad54b016e365dfefa017764a76f4f3eb
|
|
3381
|
+
type: script
|
|
3382
|
+
size: 4089
|
|
3375
3383
|
- path: infrastructure/scripts/template-engine.js
|
|
3376
3384
|
hash: sha256:de1bc8ce51eeabf6f6ec558d35107fbc4843ac76e3361044ba9f47bb6af4f058
|
|
3377
3385
|
type: script
|
|
@@ -3420,22 +3428,34 @@ files:
|
|
|
3420
3428
|
hash: sha256:4447fbf8cffdf20b34fad71eb4caf5aec0726f2b8f27cd49cd1bd59d69cdc009
|
|
3421
3429
|
type: script
|
|
3422
3430
|
size: 2838
|
|
3431
|
+
- path: infrastructure/scripts/validate-codex-command-registry.js
|
|
3432
|
+
hash: sha256:a37a4c5fc8a4c3a7ce7ba240aeea16abc0a75871751f66eeb84991604ff066bf
|
|
3433
|
+
type: script
|
|
3434
|
+
size: 7266
|
|
3435
|
+
- path: infrastructure/scripts/validate-codex-delegation.js
|
|
3436
|
+
hash: sha256:a71224ad31b3a28bcc26953f75bbd6387686b3b906404c833f52b8dfff306384
|
|
3437
|
+
type: script
|
|
3438
|
+
size: 9532
|
|
3423
3439
|
- path: infrastructure/scripts/validate-codex-integration.js
|
|
3424
|
-
hash: sha256:
|
|
3440
|
+
hash: sha256:c553cc493ddbfecf41b865f8a1075df56b6500c3b2b315bae8b7e7bcec4db85a
|
|
3441
|
+
type: script
|
|
3442
|
+
size: 4742
|
|
3443
|
+
- path: infrastructure/scripts/validate-codex-sync.js
|
|
3444
|
+
hash: sha256:31bcfc0cdf307e7c14064eaf0ddbf99a14344c21306937c9a7d9cc7ebba260f8
|
|
3425
3445
|
type: script
|
|
3426
|
-
size:
|
|
3446
|
+
size: 4679
|
|
3427
3447
|
- path: infrastructure/scripts/validate-output-pattern.js
|
|
3428
3448
|
hash: sha256:91111d656e8d7b38a20a1bda753e663b74318f75cdab2025c7e0b84c775fc83d
|
|
3429
3449
|
type: script
|
|
3430
3450
|
size: 6692
|
|
3431
3451
|
- path: infrastructure/scripts/validate-parity.js
|
|
3432
|
-
hash: sha256:
|
|
3452
|
+
hash: sha256:284c7715cc65b76579284024bbe5176b9230340d841dbfe79559c8f5844109cb
|
|
3433
3453
|
type: script
|
|
3434
|
-
size:
|
|
3454
|
+
size: 12266
|
|
3435
3455
|
- path: infrastructure/scripts/validate-paths.js
|
|
3436
|
-
hash: sha256:
|
|
3456
|
+
hash: sha256:942f6de9e621b7331f61dc915db5d24b987b67d1ae3377882330f7013dd214e9
|
|
3437
3457
|
type: script
|
|
3438
|
-
size:
|
|
3458
|
+
size: 3671
|
|
3439
3459
|
- path: infrastructure/scripts/validate-user-profile.js
|
|
3440
3460
|
hash: sha256:0f78a5aebd85b4b0d2a5b0f2d81ccbbbe0f2d25ed1cfcafeb129734852217683
|
|
3441
3461
|
type: script
|
|
@@ -3525,9 +3545,9 @@ files:
|
|
|
3525
3545
|
type: template
|
|
3526
3546
|
size: 338
|
|
3527
3547
|
- path: infrastructure/templates/safe-collab/README.md
|
|
3528
|
-
hash: sha256:
|
|
3548
|
+
hash: sha256:0b4f3d0ce9b7111d812917312ae504df976245d902eecfa501f73e7aa0719813
|
|
3529
3549
|
type: template
|
|
3530
|
-
size:
|
|
3550
|
+
size: 2179
|
|
3531
3551
|
- path: infrastructure/templates/safe-collab/safe-collaboration-rule.md
|
|
3532
3552
|
hash: sha256:9631681340fddc314080f9182b76ccfbb1ee3441d92ce181067e76cace960a5e
|
|
3533
3553
|
type: template
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execFileSync, execSync } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
function execGit(command) {
|
|
7
|
+
return execSync(command, {
|
|
8
|
+
encoding: 'utf8',
|
|
9
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
10
|
+
}).trim();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function safeExec(command) {
|
|
14
|
+
try {
|
|
15
|
+
return execGit(command);
|
|
16
|
+
} catch {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseArgs(argv) {
|
|
22
|
+
const parsed = {
|
|
23
|
+
adoptCurrent: false,
|
|
24
|
+
check: false,
|
|
25
|
+
type: 'feat',
|
|
26
|
+
owner: null,
|
|
27
|
+
storyId: null,
|
|
28
|
+
slug: null,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
for (const arg of argv) {
|
|
32
|
+
if (arg === '--adopt-current') {
|
|
33
|
+
parsed.adoptCurrent = true;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (arg === '--check') {
|
|
37
|
+
parsed.check = true;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (arg.startsWith('--type=')) {
|
|
41
|
+
parsed.type = arg.split('=')[1] || parsed.type;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (arg.startsWith('--owner=')) {
|
|
45
|
+
parsed.owner = arg.split('=')[1] || null;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (!parsed.storyId) {
|
|
49
|
+
parsed.storyId = arg;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!parsed.slug) {
|
|
53
|
+
parsed.slug = arg;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return parsed;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function resolveDefaultBranch() {
|
|
61
|
+
try {
|
|
62
|
+
const remoteHead = execGit('git symbolic-ref --short refs/remotes/origin/HEAD');
|
|
63
|
+
return remoteHead.replace(/^origin\//, '');
|
|
64
|
+
} catch {
|
|
65
|
+
return 'main';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getCurrentBranch() {
|
|
70
|
+
return execGit('git rev-parse --abbrev-ref HEAD');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getStatusLines() {
|
|
74
|
+
const output = safeExec('git status --porcelain');
|
|
75
|
+
return output ? output.split('\n').filter(Boolean) : [];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function sanitizeSegment(value) {
|
|
79
|
+
return String(value || '')
|
|
80
|
+
.trim()
|
|
81
|
+
.toLowerCase()
|
|
82
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
83
|
+
.replace(/^-+|-+$/g, '')
|
|
84
|
+
.replace(/-{2,}/g, '-');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function detectOwnerPrefix(explicitOwner) {
|
|
88
|
+
if (explicitOwner) {
|
|
89
|
+
return sanitizeSegment(explicitOwner) || 'dev';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const rawSignals = [
|
|
93
|
+
safeExec('git config user.name'),
|
|
94
|
+
safeExec('git config user.email'),
|
|
95
|
+
process.env.USERNAME || '',
|
|
96
|
+
process.env.USER || '',
|
|
97
|
+
]
|
|
98
|
+
.join(' ')
|
|
99
|
+
.toLowerCase();
|
|
100
|
+
|
|
101
|
+
if (/(caio|imori)/.test(rawSignals)) {
|
|
102
|
+
return 'caio';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (/(matheus|soier|sawyer)/.test(rawSignals)) {
|
|
106
|
+
return 'soier';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return 'dev';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function buildWorkItemSlug(storyId, slug) {
|
|
113
|
+
const sanitizedStory = sanitizeSegment(storyId);
|
|
114
|
+
const sanitizedSlug = sanitizeSegment(slug || storyId);
|
|
115
|
+
if (!sanitizedSlug) {
|
|
116
|
+
return sanitizedStory;
|
|
117
|
+
}
|
|
118
|
+
if (!sanitizedStory) {
|
|
119
|
+
return sanitizedSlug;
|
|
120
|
+
}
|
|
121
|
+
return sanitizedSlug.startsWith(`${sanitizedStory}-`) || sanitizedSlug === sanitizedStory
|
|
122
|
+
? sanitizedSlug
|
|
123
|
+
: `${sanitizedStory}-${sanitizedSlug}`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function buildBranchName({ owner, type, storyId, slug }) {
|
|
127
|
+
return `${owner}/${sanitizeSegment(type) || 'feat'}/${buildWorkItemSlug(storyId, slug)}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function buildWorktreePath(worktreeKey) {
|
|
131
|
+
return path.join(process.cwd(), '.sinapse', 'worktrees', worktreeKey);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function ensureReadyDefaultBranch(defaultBranch) {
|
|
135
|
+
const branchName = getCurrentBranch();
|
|
136
|
+
const statusLines = getStatusLines();
|
|
137
|
+
|
|
138
|
+
if (branchName !== defaultBranch) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`Run collab:start from a clean '${defaultBranch}' checkout. Current branch: '${branchName}'.`,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (statusLines.length > 0) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Working tree is dirty on '${defaultBranch}'. Commit or stash your changes before opening a new worktree.`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function ensureOnDefaultBranch(defaultBranch) {
|
|
152
|
+
const branchName = getCurrentBranch();
|
|
153
|
+
if (branchName !== defaultBranch) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`Run this command from '${defaultBranch}'. Current branch: '${branchName}'.`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function ensureUpToDate(defaultBranch) {
|
|
161
|
+
execFileSync('git', ['fetch', 'origin'], {
|
|
162
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const localSha = safeExec(`git rev-parse ${defaultBranch}`);
|
|
166
|
+
const remoteSha = safeExec(`git rev-parse origin/${defaultBranch}`);
|
|
167
|
+
|
|
168
|
+
if (localSha && remoteSha && localSha !== remoteSha) {
|
|
169
|
+
execFileSync('git', ['pull', '--ff-only', 'origin', defaultBranch], {
|
|
170
|
+
stdio: 'inherit',
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function createWorktree({ branchName, defaultBranch, worktreePath }) {
|
|
176
|
+
execFileSync('git', ['worktree', 'add', worktreePath, '-b', branchName, defaultBranch], {
|
|
177
|
+
stdio: 'inherit',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function adoptCurrentWorkspace(branchName) {
|
|
182
|
+
execFileSync('git', ['checkout', '-b', branchName], {
|
|
183
|
+
stdio: 'inherit',
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function runCheck() {
|
|
188
|
+
const defaultBranch = resolveDefaultBranch();
|
|
189
|
+
const currentBranch = getCurrentBranch();
|
|
190
|
+
const statusLines = getStatusLines();
|
|
191
|
+
const owner = detectOwnerPrefix(null);
|
|
192
|
+
|
|
193
|
+
console.log(`Default branch: ${defaultBranch}`);
|
|
194
|
+
console.log(`Current branch: ${currentBranch}`);
|
|
195
|
+
console.log(`Detected maintainer prefix: ${owner}`);
|
|
196
|
+
console.log(`Working tree clean: ${statusLines.length === 0 ? 'yes' : 'no'}`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function main() {
|
|
200
|
+
const args = parseArgs(process.argv.slice(2));
|
|
201
|
+
if (args.check) {
|
|
202
|
+
runCheck();
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (!args.storyId) {
|
|
207
|
+
console.error(
|
|
208
|
+
'Usage: npm run collab:start -- <story-id> <slug> [--type=feat] [--owner=caio] [--adopt-current]',
|
|
209
|
+
);
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const defaultBranch = resolveDefaultBranch();
|
|
214
|
+
const owner = detectOwnerPrefix(args.owner);
|
|
215
|
+
const branchName = buildBranchName({
|
|
216
|
+
owner,
|
|
217
|
+
type: args.type,
|
|
218
|
+
storyId: args.storyId,
|
|
219
|
+
slug: args.slug,
|
|
220
|
+
});
|
|
221
|
+
const worktreeKey = sanitizeSegment(branchName.replace(/\//g, '-'));
|
|
222
|
+
const worktreePath = buildWorktreePath(worktreeKey);
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
if (args.adoptCurrent) {
|
|
226
|
+
ensureOnDefaultBranch(defaultBranch);
|
|
227
|
+
adoptCurrentWorkspace(branchName);
|
|
228
|
+
} else {
|
|
229
|
+
ensureReadyDefaultBranch(defaultBranch);
|
|
230
|
+
ensureUpToDate(defaultBranch);
|
|
231
|
+
createWorktree({ branchName, defaultBranch, worktreePath });
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error('');
|
|
235
|
+
console.error(`collab:start failed: ${error.message}`);
|
|
236
|
+
console.error('');
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
console.log('');
|
|
241
|
+
if (args.adoptCurrent) {
|
|
242
|
+
console.log('Current workspace adopted into a safe maintainer branch.');
|
|
243
|
+
console.log(`Branch: ${branchName}`);
|
|
244
|
+
console.log('');
|
|
245
|
+
console.log('Continue working in the current directory, now outside main.');
|
|
246
|
+
} else {
|
|
247
|
+
console.log('Safe maintainer workspace created.');
|
|
248
|
+
console.log(`Branch: ${branchName}`);
|
|
249
|
+
console.log(`Worktree: ${worktreePath}`);
|
|
250
|
+
console.log('');
|
|
251
|
+
console.log(`Next step: cd "${worktreePath}"`);
|
|
252
|
+
}
|
|
253
|
+
console.log('');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
module.exports = {
|
|
257
|
+
buildBranchName,
|
|
258
|
+
buildWorkItemSlug,
|
|
259
|
+
detectOwnerPrefix,
|
|
260
|
+
parseArgs,
|
|
261
|
+
resolveDefaultBranch,
|
|
262
|
+
sanitizeSegment,
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
if (require.main === module) {
|
|
266
|
+
main();
|
|
267
|
+
}
|