@1aboveio/skills 1.0.10 → 1.0.12
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-plugin/plugin.json +1 -1
- package/.codex-plugin/resources.json +298 -216
- package/README.md +3 -3
- package/package.json +10 -8
- package/skills/app-dev/airflow/SKILL.md +1 -1
- package/skills/app-dev/android-foundation/SKILL.md +35 -37
- package/skills/app-dev/android-foundation/references/delivery-focus.md +4 -2
- package/skills/app-dev/android-foundation/references/feature-work.md +50 -0
- package/skills/app-dev/android-foundation/references/setup.md +24 -9
- package/skills/app-dev/android-foundation/references/workspace.md +81 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/bin/workspaces.mjs +52 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/native-workspace.mjs +239 -0
- package/skills/app-dev/android-foundation/scripts/workspace-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/app-dev/app-debug/SKILL.md +1 -1
- package/skills/app-dev/better-auth/SKILL.md +1 -1
- package/skills/app-dev/data-catalog/SKILL.md +1 -1
- package/skills/app-dev/data-quality/SKILL.md +1 -1
- package/skills/app-dev/ios-foundation/SKILL.md +15 -10
- package/skills/app-dev/ios-foundation/references/setup.md +25 -9
- package/skills/app-dev/ios-foundation/references/workspace.md +82 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/bin/workspaces.mjs +52 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/native-workspace.mjs +239 -0
- package/skills/app-dev/ios-foundation/scripts/workspace-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/app-dev/monorepo/SKILL.md +1 -1
- package/skills/app-dev/nextjs-fullstack/SKILL.md +1 -1
- package/skills/app-dev/prisma-setup/SKILL.md +1 -1
- package/skills/app-dev/pyspark/SKILL.md +1 -1
- package/skills/app-dev/python-backend/SKILL.md +1 -1
- package/skills/app-dev/shadcn/SKILL.md +1 -1
- package/skills/app-dev/zod-v4/SKILL.md +1 -1
- package/skills/cicd/cloud-build/SKILL.md +1 -1
- package/skills/cicd/cloud-debug/SKILL.md +1 -1
- package/skills/cicd/cloud-deploy/SKILL.md +1 -1
- package/skills/cicd/docker/SKILL.md +1 -1
- package/skills/cicd/github-actions/SKILL.md +1 -1
- package/skills/cicd/github-flow/SKILL.md +1 -1
- package/skills/cicd/google-cloud/SKILL.md +1 -1
- package/skills/cicd/mergify/SKILL.md +1 -1
- package/skills/cicd/podman/SKILL.md +1 -1
- package/skills/content/article-review/SKILL.md +1 -1
- package/skills/content/article-to-image/SKILL.md +1 -1
- package/skills/content/flowchart-svg/SKILL.md +1 -1
- package/skills/content/image-gen/SKILL.md +1 -1
- package/skills/content/mermaid/SKILL.md +1 -1
- package/skills/content/wechat-article-writer/SKILL.md +1 -1
- package/skills/content/wechat-publisher/SKILL.md +1 -1
- package/skills/content/wechat-search/SKILL.md +1 -1
- package/skills/content/xai-search/SKILL.md +1 -1
- package/skills/core/distill-writing/SKILL.md +3 -3
- package/skills/core/distill-writing/references/extraction.md +1 -1
- package/skills/core/doc-to-md/SKILL.md +1 -1
- package/skills/core/editorial-review/SKILL.md +82 -12
- package/skills/core/editorial-review/references/checklist.md +26 -1
- package/skills/core/house-style/SKILL.md +8 -3
- package/skills/core/house-style/references/analytical-reporting.md +123 -0
- package/skills/core/house-style/references/analytical-writing-patterns.md +79 -0
- package/skills/core/house-style/references/analytical-writing-research.md +129 -0
- package/skills/core/{write-doc → house-style}/references/bilingual.md +7 -5
- package/skills/core/house-style/references/definitions-and-metrics.md +86 -0
- package/skills/core/house-style/references/document-workflow.md +193 -0
- package/skills/core/house-style/references/initialization.md +66 -0
- package/skills/core/house-style/references/persistence.md +9 -4
- package/skills/core/house-style/references/rules.md +11 -4
- package/skills/core/house-style/scripts/init-guidance.mjs +213 -0
- package/skills/core/house-style/templates/analytical-report.md +54 -0
- package/skills/core/house-style/templates/gap-analysis.md +1 -1
- package/skills/core/plain-language/SKILL.md +2 -2
- package/skills/core/polish-cn/SKILL.md +9 -2
- package/skills/core/reg-parser/SKILL.md +3 -3
- package/skills/core/terminology/SKILL.md +8 -4
- package/skills/core/write-doc/SKILL.md +40 -151
- package/skills/core/write-report/SKILL.md +129 -0
- package/skills/core/{write-doc → write-report}/references/compliance-reports.md +4 -4
- package/skills/engineering/better-review/SKILL.md +37 -37
- package/skills/engineering/better-review/references/passes.md +35 -41
- package/skills/engineering/better-review/references/result.md +10 -9
- package/skills/engineering/e2e-test/SKILL.md +17 -17
- package/skills/engineering/e2e-test/references/authoring/playwright-config.md +11 -13
- package/skills/engineering/e2e-test/references/presentation-sweep.md +7 -7
- package/skills/engineering/e2e-test/references/reviewing.md +9 -11
- package/skills/engineering/e2e-test/references/route-manifest.md +1 -1
- package/skills/engineering/engineering/SKILL.md +201 -0
- package/skills/engineering/engineering/references/engineering-conventions.md +32 -0
- package/skills/engineering/engineering/references/feature-delivery.md +8 -0
- package/skills/engineering/engineering/references/init-scope.md +45 -0
- package/skills/engineering/engineering/references/scope-management.md +85 -0
- package/skills/engineering/engineering/scripts/init.mjs +160 -0
- package/skills/engineering/{contributing → engineering}/scripts/persist-conventions.mjs +1 -1
- package/skills/engineering/engineering-runtime/SKILL.md +1 -1
- package/skills/engineering/engineering-runtime/coherence/workflow.json +19 -19
- package/skills/engineering/engineering-runtime/scripts/workflow-policy.mjs +1 -1
- package/skills/engineering/ensure-coverage/SKILL.md +22 -109
- package/skills/engineering/ensure-coverage/references/breadth/coverage-ledger.md +7 -5
- package/skills/engineering/ensure-coverage/references/breadth/surface-baseline.md +4 -4
- package/skills/engineering/ensure-coverage/references/breadth/surface-discovery.md +3 -3
- package/skills/engineering/ensure-coverage/references/depth/characterization.md +4 -65
- package/skills/engineering/ensure-coverage/references/depth/grading.md +5 -7
- package/skills/engineering/ensure-coverage/references/depth/mock-policy.md +6 -12
- package/skills/engineering/ensure-coverage/references/enforcement/ci-contract.md +1 -1
- package/skills/engineering/ensure-coverage/references/presentation/axis.md +6 -6
- package/skills/engineering/ensure-coverage/references/process/audit-mode.md +7 -23
- package/skills/engineering/ensure-coverage/references/process/output-template.md +18 -133
- package/skills/engineering/ensure-coverage/references/process/test-strategy.md +7 -12
- package/skills/engineering/ensure-coverage/scripts/README.md +12 -4
- package/skills/engineering/golden-path/SKILL.md +1 -1
- package/skills/engineering/harness-runtime/SKILL.md +3 -1
- package/skills/engineering/harness-runtime/bin/workspaces.mjs +52 -0
- package/skills/engineering/harness-runtime/native-workspace.mjs +239 -0
- package/skills/engineering/harness-runtime/references/workspaces.md +78 -0
- package/skills/engineering/harness-runtime/workspace-lifecycle.mjs +2154 -0
- package/skills/engineering/resolve-issues/SKILL.md +40 -61
- package/skills/engineering/resolve-issues/references/ci.md +13 -3
- package/skills/engineering/resolve-issues/references/delivery-progress.md +4 -3
- package/skills/engineering/resolve-issues/references/done.md +11 -2
- package/skills/engineering/resolve-issues/references/expire.md +9 -2
- package/skills/engineering/resolve-issues/references/implementation.md +33 -17
- package/skills/engineering/resolve-issues/references/preflight.md +3 -1
- package/skills/engineering/resolve-issues/references/principles.md +52 -0
- package/skills/engineering/resolve-issues/references/review.md +25 -15
- package/skills/engineering/resolve-issues/references/task-plan.md +64 -27
- package/skills/engineering/resolve-issues/references/workspaces.md +164 -0
- package/skills/engineering/resolve-issues/scripts/cleanup-runs.mjs +185 -317
- package/skills/engineering/resolve-issues/scripts/next-actions.mjs +44 -7
- package/skills/engineering/resolve-issues/scripts/rehydrate.mjs +36 -2
- package/skills/engineering/resolve-issues/scripts/review-verdict.mjs +9 -8
- package/skills/engineering/resolve-issues/scripts/workspace-lifecycle.mjs +1 -0
- package/skills/engineering/resolve-release/SKILL.md +1 -1
- package/skills/engineering/rush-issues/SKILL.md +7 -5
- package/skills/engineering/rush-release/SKILL.md +1 -1
- package/skills/engineering/test-quality/SKILL.md +19 -4
- package/skills/engineering/test-quality/references/lint.md +1 -1
- package/skills/engineering/test-quality/references/principles.md +2 -2
- package/skills/engineering/test-quality/references/testing-conventions.md +1 -1
- package/skills/risk-compliance/compliance-audit/SKILL.md +4 -8
- package/skills/risk-compliance/compliance-audit/references/audience-and-reports.md +12 -0
- package/skills/risk-compliance/contract-compare/SKILL.md +17 -1
- package/skills/risk-compliance/contract-review/SKILL.md +6 -1
- package/skills/risk-compliance/contract-review/references/report-stage.md +17 -0
- package/skills/risk-compliance/doc-authenticity/SKILL.md +11 -1
- package/skills/risk-compliance/fraud-detection/LICENSE +3 -0
- package/skills/risk-compliance/fraud-detection/SKILL.md +148 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/archetypes/first-party-fraud.md +3 -2
- package/skills/risk-compliance/fraud-detection/references/archetypes/third-party-fraud.md +47 -0
- package/skills/risk-compliance/fraud-detection/references/collection-payout-features.md +151 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/contexts/bank-transfer.md +4 -3
- package/skills/risk-compliance/fraud-detection/references/contexts/card-payment.md +70 -0
- package/skills/risk-compliance/fraud-detection/references/contexts/payment-collection.md +34 -0
- package/skills/risk-compliance/fraud-detection/references/contexts/payout.md +34 -0
- package/skills/risk-compliance/fraud-detection/references/enrichment.md +74 -0
- package/skills/risk-compliance/fraud-detection/references/entities.md +48 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/feature-engineering.md +69 -33
- package/skills/risk-compliance/fraud-detection/references/feature-sql.md +150 -0
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/report-rationale.md +4 -2
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/report-template.md +45 -23
- package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/review-checklist.md +60 -20
- package/skills/risk-compliance/fraud-detection/references/workflow.md +216 -0
- package/skills/risk-compliance/fraud-detection/release-check.mjs +95 -0
- package/skills/risk-compliance/payment-analysis/SKILL.md +36 -17
- package/skills/risk-compliance/payment-analysis/references/auth-rate-actions.md +2 -2
- package/skills/risk-compliance/payment-analysis/references/report-template.md +10 -2
- package/skills/risk-compliance/payment-analysis/references/visualization.md +11 -1
- package/skills/risk-compliance/portfolio-payment-analysis/LICENSE +3 -0
- package/skills/risk-compliance/portfolio-payment-analysis/SKILL.md +170 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/identity-and-reconciliation.md +46 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/metrics-and-reporting.md +170 -0
- package/skills/risk-compliance/portfolio-payment-analysis/references/risk-history.md +89 -0
- package/skills/risk-compliance/portfolio-payment-analysis/release-check.mjs +95 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/analyze.py +636 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/build_report.py +386 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/comparison_charts.py +425 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/csv_export.py +52 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/render.py +160 -0
- package/skills/risk-compliance/portfolio-payment-analysis/scripts/risk_history.py +435 -0
- package/skills/risk-compliance/similar-domain/SKILL.md +9 -4
- package/skills/risk-compliance/tld-detection/SKILL.md +124 -239
- package/skills/risk-compliance/tld-detection/agents/openai.yaml +1 -1
- package/skills/risk-compliance/tld-detection/references/clean.md +18 -51
- package/skills/risk-compliance/tld-detection/references/fx-conversion.md +56 -219
- package/skills/risk-compliance/tld-detection/references/metric-contract.md +109 -0
- package/skills/risk-compliance/tld-detection/references/pattern.md +99 -0
- package/skills/risk-compliance/tld-detection/references/report-template.md +49 -272
- package/skills/risk-compliance/tld-detection/scripts/detect_ladders.py +46 -13
- package/skills/risk-compliance/tld-detection/scripts/detect_patterns.py +346 -0
- package/skills/risk-compliance/tld-detection/scripts/detect_streams.py +51 -19
- package/skills/risk-compliance/tld-detection/scripts/profile_groups.py +109 -0
- package/skills/risk-compliance/tld-detection/scripts/render_charts.py +218 -0
- package/skills/risk-compliance/tld-detection/scripts/tld_common.py +243 -0
- package/skills/engineering/contributing/SKILL.md +0 -70
- package/skills/risk-compliance/fraud-analysis/SKILL.md +0 -114
- package/skills/risk-compliance/fraud-analysis/references/archetypes/third-party-fraud.md +0 -27
- package/skills/risk-compliance/fraud-analysis/references/contexts/card-payment.md +0 -30
- package/skills/risk-compliance/fraud-analysis/references/contexts/payment-collection.md +0 -20
- package/skills/risk-compliance/fraud-analysis/references/contexts/payout.md +0 -20
- package/skills/risk-compliance/fraud-analysis/references/workflow.md +0 -175
- package/skills/risk-compliance/tld-detection/references/chinese-polish.md +0 -55
- package/skills/risk-compliance/tld-detection/references/clustering.md +0 -235
- package/skills/risk-compliance/tld-detection/references/decision.md +0 -189
- package/skills/risk-compliance/tld-detection/references/streams.md +0 -141
- package/skills/risk-compliance/tld-detection/references/terminology.md +0 -95
- package/skills/risk-compliance/tld-detection/references/workflow.md +0 -95
- /package/skills/{engineering/contributing → core/write-report}/LICENSE +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/audit-report-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/external-assessment-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/management-report-template.md +0 -0
- /package/skills/core/{write-doc → write-report}/references/reports/vars-report-template.md +0 -0
- /package/skills/{engineering/contributing → core/write-report}/release-check.mjs +0 -0
- /package/skills/{risk-compliance/fraud-analysis → engineering/engineering}/LICENSE +0 -0
- /package/skills/engineering/{contributing → engineering}/references/tracker-conventions.md +0 -0
- /package/skills/{risk-compliance/fraud-analysis → engineering/engineering}/release-check.mjs +0 -0
- /package/skills/engineering/{contributing → engineering}/scripts/persist-conventions-core.mjs +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/archetypes/authorized-payment-scam.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/mechanisms/account-takeover.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/taxonomy.md +0 -0
- /package/skills/risk-compliance/{fraud-analysis → fraud-detection}/references/terminology.md +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { execFileSync, spawnSync } from 'node:child_process'
|
|
2
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, renameSync, rmdirSync, unlinkSync, writeFileSync } from 'node:fs'
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'
|
|
4
|
+
import { randomUUID } from 'node:crypto'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
|
|
7
|
+
const cli = fileURLToPath(new URL('./bin/workspaces.mjs', import.meta.url))
|
|
8
|
+
const git = (cwd, ...args) => execFileSync('git', ['-C', cwd, ...args], { encoding: 'utf8', timeout: 30_000, stdio: ['ignore', 'pipe', 'pipe'] }).trim()
|
|
9
|
+
const component = (value) => typeof value === 'string' && /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(value) && value !== '.' && value !== '..'
|
|
10
|
+
|
|
11
|
+
function stat(path) {
|
|
12
|
+
try { return lstatSync(path) } catch (error) { if (error.code === 'ENOENT') return null; throw error }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function noLinks(root, path) {
|
|
16
|
+
const rel = relative(root, path)
|
|
17
|
+
if (rel.startsWith(`..${sep}`) || rel === '..' || isAbsolute(rel)) throw new Error('workspace path escapes its repository')
|
|
18
|
+
let current = root
|
|
19
|
+
for (const part of rel.split(sep).filter(Boolean)) {
|
|
20
|
+
current = join(current, part)
|
|
21
|
+
if (stat(current)?.isSymbolicLink()) throw new Error(`symlink in managed path: ${current}`)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// This lock owns the plan, including initial creation. The engine independently locks
|
|
26
|
+
// workspace operations; its shorter lock cannot protect our read/modify/write cycle.
|
|
27
|
+
function withOwner(repo, run, operation) {
|
|
28
|
+
const locks = join(dirname(run), '.native-locks')
|
|
29
|
+
const lock = join(locks, basename(run))
|
|
30
|
+
noLinks(repo, run)
|
|
31
|
+
noLinks(repo, lock)
|
|
32
|
+
mkdirSync(locks, { recursive: true })
|
|
33
|
+
try { mkdirSync(lock) } catch (error) {
|
|
34
|
+
if (error.code !== 'EEXIST') throw error
|
|
35
|
+
let owner = 'unknown owner'
|
|
36
|
+
try { owner = `owner PID ${JSON.parse(readFileSync(join(lock, 'owner.json'), 'utf8')).pid ?? 'unknown'}` } catch { /* Unknown owners also block. */ }
|
|
37
|
+
throw new Error(`native run is locked at ${lock} (${owner}); locks are never reclaimed by age`)
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
writeFileSync(join(lock, 'owner.json'), `${JSON.stringify({ pid: process.pid, run, at: new Date().toISOString() })}\n`, { flag: 'wx', mode: 0o600 })
|
|
41
|
+
return operation()
|
|
42
|
+
} finally {
|
|
43
|
+
try { unlinkSync(join(lock, 'owner.json')) } catch (error) {
|
|
44
|
+
if (error.code !== 'ENOENT') throw error
|
|
45
|
+
} finally {
|
|
46
|
+
rmdirSync(lock)
|
|
47
|
+
try { rmdirSync(locks) } catch (error) { if (!['ENOTEMPTY', 'ENOENT', 'EEXIST'].includes(error.code)) throw error }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function planStore(repo, run) {
|
|
53
|
+
const file = join(run, 'task-plan.json')
|
|
54
|
+
const read = () => {
|
|
55
|
+
noLinks(repo, file)
|
|
56
|
+
return stat(file) ? readFileSync(file, 'utf8') : null
|
|
57
|
+
}
|
|
58
|
+
let expected = read()
|
|
59
|
+
const plan = expected === null ? null : JSON.parse(expected)
|
|
60
|
+
let revision = plan?.planRevision ?? -1
|
|
61
|
+
return {
|
|
62
|
+
plan,
|
|
63
|
+
save(next) {
|
|
64
|
+
if (read() !== expected || (expected !== null && JSON.parse(expected).planRevision !== revision)) {
|
|
65
|
+
throw new Error('native plan revision/content changed; refusing to overwrite another owner')
|
|
66
|
+
}
|
|
67
|
+
next.planRevision = revision + 1
|
|
68
|
+
const text = `${JSON.stringify(next, null, 2)}\n`
|
|
69
|
+
const temp = `${file}.${randomUUID()}.tmp`
|
|
70
|
+
try {
|
|
71
|
+
writeFileSync(temp, text, { flag: 'wx', mode: 0o600 })
|
|
72
|
+
if (read() !== expected) throw new Error('native plan changed before persist; refusing to overwrite another owner')
|
|
73
|
+
renameSync(temp, file)
|
|
74
|
+
expected = text
|
|
75
|
+
revision = next.planRevision
|
|
76
|
+
} finally {
|
|
77
|
+
if (stat(temp)) unlinkSync(temp)
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function ownedPlan(plan, repo, run) {
|
|
84
|
+
const unit = plan?.units?.[0]
|
|
85
|
+
if (plan?.skill !== 'native-setup' || plan.workspaceLifecycle !== 1 || plan.repoRoot !== repo || plan.runDir !== run ||
|
|
86
|
+
!Number.isSafeInteger(plan.planRevision) || plan.planRevision < 0 || plan.units?.length !== 1 || unit?.id !== 'native' ||
|
|
87
|
+
unit.workspace !== join(run, 'units', 'native') || unit.lifecycle?.version !== 1 ||
|
|
88
|
+
!['worktree', 'clone'].includes(unit.lifecycle.workspace?.kind) || !/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(unit.lifecycle.workspace?.baseSha ?? '') ||
|
|
89
|
+
unit.base !== unit.lifecycle.workspace.baseSha || !Array.isArray(unit.lifecycle.resources)) {
|
|
90
|
+
throw new Error('not an owned standalone native run; refusing to replace its record')
|
|
91
|
+
}
|
|
92
|
+
git(repo, 'check-ref-format', '--branch', plan.targetBranch)
|
|
93
|
+
git(repo, 'check-ref-format', '--branch', unit.branch)
|
|
94
|
+
noLinks(repo, unit.workspace)
|
|
95
|
+
return unit
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function relativePath(value, label, allowRoot = false) {
|
|
99
|
+
if (allowRoot && value === '.') return value
|
|
100
|
+
if (typeof value !== 'string' || !value || isAbsolute(value) || value.includes('\\') || /[\0*?\[\]]/.test(value) ||
|
|
101
|
+
value.split('/').some((part) => !part || part === '.' || part === '..' || part === '.git' || part === '.resolve-issues')) {
|
|
102
|
+
throw new Error(`${label} must be an exact relative path without .., symlinks, or managed roots`)
|
|
103
|
+
}
|
|
104
|
+
return value
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function resourcePaths(repo, workspace, platform, nativeDir, disposable) {
|
|
108
|
+
relativePath(nativeDir, '--native-dir', true)
|
|
109
|
+
if (!Array.isArray(disposable)) throw new Error('disposable must be an array of workspace-relative paths')
|
|
110
|
+
const paths = [...new Set(['.cache', 'node_modules',
|
|
111
|
+
...(platform === 'ios' ? ['ios/Pods'] : ['android/.gradle', 'android/build', 'android/app/build']).map((path) => nativeDir === '.' ? path : `${nativeDir}/${path}`),
|
|
112
|
+
...disposable.map((path) => relativePath(path, '--disposable'))])]
|
|
113
|
+
noLinks(repo, join(repo, nativeDir))
|
|
114
|
+
noLinks(repo, join(workspace, nativeDir))
|
|
115
|
+
for (const path of paths) {
|
|
116
|
+
noLinks(repo, join(repo, path))
|
|
117
|
+
noLinks(repo, join(workspace, path))
|
|
118
|
+
}
|
|
119
|
+
return paths
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function engine(args, repo) {
|
|
123
|
+
const result = spawnSync(process.execPath, [cli, ...args, '--json'], { cwd: repo, encoding: 'utf8', timeout: 120_000, maxBuffer: 8 * 1024 * 1024 })
|
|
124
|
+
let value
|
|
125
|
+
try { value = JSON.parse(result.stdout) } catch { /* Report the failed command below. */ }
|
|
126
|
+
if (result.status === 0 || (result.status === 1 && value?.action === 'retain' && (value.lifecycle || value.nextLifecycle))) return value
|
|
127
|
+
throw new Error(result.stderr?.trim() || result.stdout?.trim() || result.error?.message || 'workspace operation failed')
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function returnedLifecycle(result) {
|
|
131
|
+
const lifecycle = result?.lifecycle ?? result?.nextLifecycle
|
|
132
|
+
if (!lifecycle || lifecycle.version !== 1) throw new Error('workspace helper returned no lifecycle transition; the recorded intent remains recoverable')
|
|
133
|
+
return lifecycle
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export function nativeStart({ repo: input, runId, base, branch, target, platform, kind, nativeDir, disposable = [] }) {
|
|
137
|
+
if (!input || !['android', 'ios'].includes(platform) || (kind !== undefined && !['worktree', 'clone'].includes(kind))) throw new Error('native-start requires --repo and --platform android|ios; --kind is worktree or clone')
|
|
138
|
+
const repo = realpathSync(resolve(input))
|
|
139
|
+
if (realpathSync(git(repo, 'rev-parse', '--show-toplevel')) !== repo) throw new Error('--repo must name the owning checkout root')
|
|
140
|
+
const id = runId ?? `native-${new Date().toISOString().replace(/[^0-9]/g, '')}-${process.pid}`
|
|
141
|
+
if (!component(id)) throw new Error('invalid native run id')
|
|
142
|
+
const run = join(repo, '.resolve-issues', 'rush', id)
|
|
143
|
+
return withOwner(repo, run, () => {
|
|
144
|
+
const store = planStore(repo, run)
|
|
145
|
+
let plan = store.plan
|
|
146
|
+
if (!plan && stat(run)) throw new Error('existing run has no ownership record; refusing to adopt it')
|
|
147
|
+
let unit
|
|
148
|
+
if (plan) {
|
|
149
|
+
unit = ownedPlan(plan, repo, run)
|
|
150
|
+
if ((base !== undefined && git(repo, 'rev-parse', '--verify', `${base}^{commit}`) !== unit.base) ||
|
|
151
|
+
(target !== undefined && target !== plan.targetBranch) || (kind !== undefined && kind !== unit.lifecycle.workspace.kind) ||
|
|
152
|
+
(branch !== undefined && branch !== unit.branch) || (nativeDir !== undefined && nativeDir !== (unit.nativeDir ?? '.'))) {
|
|
153
|
+
throw new Error('existing native run belongs to a different setup; refusing to replace it')
|
|
154
|
+
}
|
|
155
|
+
nativeDir = unit.nativeDir ?? '.'
|
|
156
|
+
} else {
|
|
157
|
+
const baseSha = git(repo, 'rev-parse', '--verify', `${base ?? 'HEAD'}^{commit}`)
|
|
158
|
+
if (!target) {
|
|
159
|
+
try { target = git(repo, 'symbolic-ref', '--short', 'refs/remotes/origin/HEAD').replace(/^origin\//, '') } catch { throw new Error('record the repository target branch with --target; origin/HEAD is unavailable') }
|
|
160
|
+
}
|
|
161
|
+
branch ??= `native/${id}`
|
|
162
|
+
kind ??= 'worktree'
|
|
163
|
+
nativeDir ??= '.'
|
|
164
|
+
git(repo, 'check-ref-format', '--branch', target)
|
|
165
|
+
git(repo, 'check-ref-format', '--branch', branch)
|
|
166
|
+
unit = { id: 'native', title: 'Standalone native setup', workspace: join(run, 'units', 'native'), branch, base: baseSha, nativeDir, disposable: [], status: 'in-flight', stage: 'implement', worker: null,
|
|
167
|
+
lifecycle: { version: 1, workspace: { kind, state: 'preparing', baseSha }, resources: [], cleanup: { state: 'pending' } } }
|
|
168
|
+
plan = { skill: 'native-setup', workspaceLifecycle: 1, repoRoot: repo, runDir: run, targetBranch: target, planRevision: 0, units: [unit] }
|
|
169
|
+
}
|
|
170
|
+
if (unit.lifecycle.cleanup?.state === 'complete') throw new Error('this setup was cleaned; start a new run rather than recreating a used workspace')
|
|
171
|
+
if (!Array.isArray(disposable) || (unit.disposable !== undefined && !Array.isArray(unit.disposable))) throw new Error('disposable must be an array of workspace-relative paths')
|
|
172
|
+
const extras = [...new Set([...(unit.disposable ?? []), ...disposable])]
|
|
173
|
+
const paths = resourcePaths(repo, unit.workspace, platform, nativeDir, extras)
|
|
174
|
+
let changed = !store.plan || unit.nativeDir === undefined || JSON.stringify(unit.disposable) !== JSON.stringify(extras)
|
|
175
|
+
unit.nativeDir = nativeDir
|
|
176
|
+
unit.disposable = extras
|
|
177
|
+
for (const item of paths) {
|
|
178
|
+
const path = join(unit.workspace, item)
|
|
179
|
+
if (unit.lifecycle.resources.some((r) => r.path === path)) continue
|
|
180
|
+
unit.lifecycle.resources.push({ path, role: 'scratch', kind: 'directory', disposable: true, state: 'preparing' })
|
|
181
|
+
changed = true
|
|
182
|
+
}
|
|
183
|
+
if (!store.plan) mkdirSync(run)
|
|
184
|
+
if (changed) store.save(plan)
|
|
185
|
+
const result = engine(['prepare', '--run', run, '--unit', 'native', '--revision', String(plan.planRevision), '--apply'], repo)
|
|
186
|
+
unit.lifecycle = returnedLifecycle(result)
|
|
187
|
+
store.save(plan)
|
|
188
|
+
return { ...result, run, runId: id, workspace: unit.workspace, nativeDir, disposable: extras, sourceSha: git(unit.workspace, 'rev-parse', 'HEAD'), planRevision: plan.planRevision }
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function nativeFinish({ run: input }) {
|
|
193
|
+
if (!input) throw new Error('native-finish requires --run')
|
|
194
|
+
const run = resolve(input)
|
|
195
|
+
const repo = realpathSync(join(run, '..', '..', '..'))
|
|
196
|
+
if (!component(basename(run)) || run !== join(repo, '.resolve-issues', 'rush', basename(run))) throw new Error('not an owned standalone native run')
|
|
197
|
+
noLinks(repo, run)
|
|
198
|
+
if (!stat(run)?.isDirectory()) throw new Error('native run does not exist')
|
|
199
|
+
return withOwner(repo, run, () => {
|
|
200
|
+
const store = planStore(repo, run)
|
|
201
|
+
const plan = store.plan
|
|
202
|
+
const unit = ownedPlan(plan, repo, run)
|
|
203
|
+
// Completed and interrupted removals still go through the engine's postcondition
|
|
204
|
+
// checks, including owned resources outside the workspace and cleanup receipts.
|
|
205
|
+
const completeCleanup = () => {
|
|
206
|
+
const result = engine(['cleanup', '--run', run, '--unit', 'native', '--revision', String(plan.planRevision), '--apply'], repo)
|
|
207
|
+
const lifecycle = returnedLifecycle(result)
|
|
208
|
+
if (result.ok !== false && (lifecycle.cleanup?.state !== 'complete' || existsSync(unit.workspace) || lifecycle.resources.some((r) => existsSync(r.path)))) {
|
|
209
|
+
throw new Error('cleanup has not reached its postconditions; the recorded intent remains recoverable')
|
|
210
|
+
}
|
|
211
|
+
unit.lifecycle = lifecycle
|
|
212
|
+
store.save(plan)
|
|
213
|
+
return { ...result, run, planRevision: plan.planRevision }
|
|
214
|
+
}
|
|
215
|
+
if (unit.lifecycle.cleanup?.state === 'complete' || (!existsSync(unit.workspace) && unit.lifecycle.cleanup?.state === 'applying')) return completeCleanup()
|
|
216
|
+
const headSha = git(unit.workspace, 'rev-parse', 'HEAD')
|
|
217
|
+
const remote = git(repo, 'remote', 'get-url', 'origin')
|
|
218
|
+
git(unit.workspace, 'fetch', '--no-tags', '--', remote, `+refs/heads/${plan.targetBranch}:refs/remotes/native-delivery/${plan.targetBranch}`)
|
|
219
|
+
const targetRef = `refs/remotes/native-delivery/${plan.targetBranch}`
|
|
220
|
+
let landed = false
|
|
221
|
+
try { git(unit.workspace, 'merge-base', '--is-ancestor', headSha, targetRef); landed = true } catch (error) {
|
|
222
|
+
if (error.status !== 1) throw error
|
|
223
|
+
}
|
|
224
|
+
if (!landed) {
|
|
225
|
+
unit.headSha = headSha
|
|
226
|
+
const reason = 'native source has not landed on the recorded remote target; retain its environment'
|
|
227
|
+
unit.lifecycle.cleanup = { state: 'retained', headSha, reason }
|
|
228
|
+
store.save(plan)
|
|
229
|
+
return { ok: false, action: 'retain', outcome: 'retained', reason, run, lifecycle: unit.lifecycle, planRevision: plan.planRevision }
|
|
230
|
+
}
|
|
231
|
+
unit.headSha = headSha
|
|
232
|
+
unit.mergeSha = headSha
|
|
233
|
+
unit.status = 'succeeded'
|
|
234
|
+
unit.delivery = 'merged'
|
|
235
|
+
unit.lifecycle.cleanup = { state: 'applying', headSha }
|
|
236
|
+
store.save(plan)
|
|
237
|
+
return completeCleanup()
|
|
238
|
+
})
|
|
239
|
+
}
|