@tera-system/core 0.1.0

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 (161) hide show
  1. package/LICENSE.md +13 -0
  2. package/MANIFEST.json +24 -0
  3. package/README.md +67 -0
  4. package/RELEASES.md +28 -0
  5. package/WELCOME.md +35 -0
  6. package/agents/application-blueprint.md +407 -0
  7. package/agents/auditor.md +665 -0
  8. package/agents/design-reviewer.md +392 -0
  9. package/agents/domain-expert-agent.md +510 -0
  10. package/agents/domain-research-agent.md +360 -0
  11. package/agents/engineering-agent-dotnet.md +218 -0
  12. package/agents/engineering-agent-phaser.md +275 -0
  13. package/agents/engineering-agent-typescript.md +300 -0
  14. package/agents/engineering-agent.md +143 -0
  15. package/agents/monitor.md +395 -0
  16. package/agents/production-erp-expert.md +506 -0
  17. package/agents/project-knowledge-agent.md +271 -0
  18. package/agents/qa-agent.md +498 -0
  19. package/agents/tera-business-transformation-consultant.md +290 -0
  20. package/agents/tera-client-engagement.md +891 -0
  21. package/agents/tera-software-designer.md +237 -0
  22. package/agents/tera-strategic-advisor.md +325 -0
  23. package/agents/tera-system-evolution.md +759 -0
  24. package/agents/tera.md +520 -0
  25. package/agents/ui-designer.md +426 -0
  26. package/commands/tera-approve.md +34 -0
  27. package/commands/tera-diagnose.md +47 -0
  28. package/commands/tera-gate.md +40 -0
  29. package/commands/tera-help.md +41 -0
  30. package/commands/tera-new-project.md +35 -0
  31. package/commands/tera-plan.md +34 -0
  32. package/commands/tera-request-build.md +45 -0
  33. package/commands/tera-resume.md +34 -0
  34. package/commands/tera-review.md +52 -0
  35. package/commands/tera-status.md +38 -0
  36. package/commands/tera-update.md +48 -0
  37. package/core/project-control/templates/TASK_TEMPLATE.md +146 -0
  38. package/core/tera-system/AGENT_ACTIVATION_MATRIX.md +285 -0
  39. package/core/tera-system/AGENT_DEPENDENCY_MAP.md +117 -0
  40. package/core/tera-system/AGENT_GENERATION_TEMPLATE.md +312 -0
  41. package/core/tera-system/AGENT_PERMISSION_MODEL.md +343 -0
  42. package/core/tera-system/AIS_PROTOCOL.md +191 -0
  43. package/core/tera-system/TERA_AGENT_CONDUCT.md +102 -0
  44. package/core/tera-system/TERA_CONTINUOUS_IMPROVEMENT_POLICY.md +111 -0
  45. package/core/tera-system/TERA_DISTRIBUTION_POLICY.md +291 -0
  46. package/core/tera-system/TERA_PROJECT_DECISION.md +281 -0
  47. package/core/tera-system/TERA_USER_GUIDE.md +462 -0
  48. package/core/tera-system/TOOLING_AND_MCP_POLICY.md +285 -0
  49. package/core/tera-system/TeraApplicationQuestionBank.md +362 -0
  50. package/core/tera-system/TeraArchitectureMap.md +91 -0
  51. package/core/tera-system/TeraClientPolicy.md +366 -0
  52. package/core/tera-system/TeraHelperAgents.md +970 -0
  53. package/core/tera-system/TeraPolicyMap.md +131 -0
  54. package/core/tera-system/TeraPreExecutionGate.md +818 -0
  55. package/core/tera-system/TeraPreparationDocumentationGovernance.md +370 -0
  56. package/core/tera-system/TeraPricingPolicy.md +674 -0
  57. package/core/tera-system/TeraProjectIntakePolicy.md +164 -0
  58. package/core/tera-system/TeraScenarioStressTests.md +168 -0
  59. package/core/tera-system/TeraSubAgents.md +854 -0
  60. package/core/tera-system/TeraSystemMaintenanceChecklist.md +80 -0
  61. package/core/tera-system/TeraTokenPolicy.md +362 -0
  62. package/core/tera-system/Tera_Project_Preparation_Files.md +1045 -0
  63. package/core/tera-system/agent-helpers/application-blueprint-details.md +177 -0
  64. package/core/tera-system/client-helpers/tera-client-engagement-discovery-domains.md +99 -0
  65. package/core/tera-system/client-helpers/tera-client-engagement-gates.md +258 -0
  66. package/core/tera-system/client-helpers/tera-client-engagement-pricing.md +341 -0
  67. package/core/tera-system/client-helpers/tera-client-engagement-protocols.md +692 -0
  68. package/core/tera-system/consulting-helpers/BTCA_METHODOLOGY_FRAMEWORK.md +195 -0
  69. package/core/tera-system/consulting-helpers/BTCA_REPORT_TEMPLATES.md +266 -0
  70. package/core/tera-system/design-system/ACCESSIBILITY_RULES.md +31 -0
  71. package/core/tera-system/design-system/COMPONENT_LIBRARY_SCHEMA.md +46 -0
  72. package/core/tera-system/design-system/DESIGN_MD_INTEGRATION.md +59 -0
  73. package/core/tera-system/design-system/DESIGN_REVIEW_STANDARDS.md +241 -0
  74. package/core/tera-system/design-system/DESIGN_SOURCE_PROTOCOL.md +61 -0
  75. package/core/tera-system/design-system/DESIGN_SYSTEM_OVERVIEW.md +66 -0
  76. package/core/tera-system/design-system/DESIGN_TOKENS_SCHEMA.md +66 -0
  77. package/core/tera-system/design-system/EXTERNAL_REFERENCE_ANALYSIS.md +52 -0
  78. package/core/tera-system/design-system/FIGMA_INTEGRATION.md +138 -0
  79. package/core/tera-system/design-system/INTERNAL_KITS_INDEX.md +26 -0
  80. package/core/tera-system/design-system/LAYOUT_PATTERNS.md +52 -0
  81. package/core/tera-system/design-system/MOBILE_UI_UX_STANDARDS.md +342 -0
  82. package/core/tera-system/design-system/RTL_LTR_RULES.md +39 -0
  83. package/core/tera-system/design-system/UI_ACCEPTANCE_GATE.md +80 -0
  84. package/core/tera-system/design-system/kits/KIT_ADMIN_DASHBOARD.md +102 -0
  85. package/core/tera-system/engineering-governance/ENGINEERING_AGENT_RESPONSIBILITIES.md +210 -0
  86. package/core/tera-system/engineering-governance/ENGINEERING_BEST_PRACTICES.md +468 -0
  87. package/core/tera-system/engineering-governance/ENGINEERING_GOVERNANCE_GATE.md +131 -0
  88. package/core/tera-system/engineering-governance/ENGINEERING_REVIEW_CHECKLIST.md +129 -0
  89. package/core/tera-system/engineering-governance/QUALITY_GATE_THRESHOLDS.md +159 -0
  90. package/core/tera-system/engineering-helpers/engineering-agent-core.md +171 -0
  91. package/core/tera-system/knowledge-base/OPENHANDS_ARCHITECTURE_REFERENCE.md +243 -0
  92. package/core/tera-system/knowledge-base/manufacturing/00_INDEX.md +32 -0
  93. package/core/tera-system/knowledge-base/manufacturing/01_MANUFACTURING_ERP_CORE_CONCEPTS.md +7 -0
  94. package/core/tera-system/knowledge-base/manufacturing/02_SAP_MANUFACTURING_RESEARCH.md +7 -0
  95. package/core/tera-system/knowledge-base/manufacturing/03_DYNAMICS_365_MANUFACTURING_RESEARCH.md +7 -0
  96. package/core/tera-system/knowledge-base/manufacturing/04_ORACLE_MANUFACTURING_RESEARCH.md +7 -0
  97. package/core/tera-system/knowledge-base/manufacturing/05_ODOO_MANUFACTURING_RESEARCH.md +7 -0
  98. package/core/tera-system/knowledge-base/manufacturing/06_ERPNEXT_MANUFACTURING_RESEARCH.md +7 -0
  99. package/core/tera-system/knowledge-base/manufacturing/07_MANUFACTURING_COSTING_GUIDE.md +7 -0
  100. package/core/tera-system/knowledge-base/manufacturing/08_PRODUCTION_DISCOVERY_QUESTIONS.md +7 -0
  101. package/core/tera-system/knowledge-base/manufacturing/09_MANUFACTURING_BLUEPRINT_CHECKLIST.md +7 -0
  102. package/core/tera-system/knowledge-base/manufacturing/10_PRODUCTION_TEST_SCENARIOS.md +7 -0
  103. package/core/tera-system/knowledge-base/manufacturing/11_QUALITY_REWORK_AND_SCRAP_GUIDE.md +7 -0
  104. package/core/tera-system/knowledge-base/manufacturing/12_MRP_AND_PLANNING_GUIDE.md +7 -0
  105. package/core/tera-system/knowledge-base/manufacturing/13_LOCAL_AND_REGIONAL_MANUFACTURING_CONTEXT.md +7 -0
  106. package/core/tera-system/knowledge-base/manufacturing/14_VENDOR_COMPARISON_MATRIX.md +7 -0
  107. package/core/tera-system/product-standards/maintenance-apps/BEST_PRACTICES_DOMAIN.md +325 -0
  108. package/core/tera-system/product-standards/maintenance-apps/STANDARD_DEFINITION.md +142 -0
  109. package/core/tera-system/profiles/PROFILES_INDEX.md +57 -0
  110. package/core/tera-system/profiles/TEMPLATE.md +47 -0
  111. package/core/tera-system/profiles/dotnet-blazor-ef.md +76 -0
  112. package/core/tera-system/profiles/dotnet-razorpages-adonet.md +137 -0
  113. package/core/tera-system/profiles/dotnet-wpf-sqlite.md +159 -0
  114. package/core/tera-system/profiles/effect-bun-opencode.md +109 -0
  115. package/core/tera-system/profiles/flutter-mobile.md +369 -0
  116. package/core/tera-system/profiles/nextjs-prisma.md +110 -0
  117. package/core/tera-system/profiles/phaser-react-node.md +302 -0
  118. package/core/tera-system/profiles/react-pwa.md +97 -0
  119. package/core/tera-system/runtime/CLIENT_DISCOVERY_PROTOCOL.md +145 -0
  120. package/core/tera-system/runtime/DOMAIN_INTELLIGENCE_PROTOCOL.md +124 -0
  121. package/core/tera-system/runtime/MVP_DEFINITION_PROTOCOL.md +176 -0
  122. package/core/tera-system/runtime/TERA_RUNTIME_CHECKLISTS.md +646 -0
  123. package/core/tera-system/runtime/TERA_RUNTIME_PROTOCOLS.md +50 -0
  124. package/core/tera-system/runtime/TERA_RUNTIME_PROTOCOLS_CLIENT.md +355 -0
  125. package/core/tera-system/runtime/TERA_RUNTIME_PROTOCOLS_CORE.md +799 -0
  126. package/core/tera-system/runtime/TERA_RUNTIME_TEMPLATES.md +908 -0
  127. package/core/tera-system/runtime/TERA_RUNTIME_TEMPLATES_DELIVERY.md +584 -0
  128. package/core/tera-system/runtime/TERA_RUNTIME_TEMPLATES_PREPARATION.md +376 -0
  129. package/core/tera-system/runtime/TERA_SOLUTION_PREPARATION_PROTOCOL.md +335 -0
  130. package/core/tera-system/runtime/TERA_SOLUTION_PREPARATION_TEMPLATES.md +397 -0
  131. package/core/tera-system/runtime/VERSION_LIFECYCLE_PROTOCOL.md +296 -0
  132. package/core/tera-system/semgrep-rules/README.md +32 -0
  133. package/core/tera-system/semgrep-rules/tera-security.yml +66 -0
  134. package/core/tera-system/semgrep-rules/tera-standards.yml +49 -0
  135. package/core/tera-system/teranoo-ui/README.md +48 -0
  136. package/core/tera-system/teranoo-ui/components/button.tsx +51 -0
  137. package/core/tera-system/teranoo-ui/components/card.tsx +49 -0
  138. package/core/tera-system/teranoo-ui/components/dashboard-layout.tsx +36 -0
  139. package/core/tera-system/teranoo-ui/components/data-table.tsx +146 -0
  140. package/core/tera-system/teranoo-ui/components/empty-state.tsx +31 -0
  141. package/core/tera-system/teranoo-ui/components/kpi-card.tsx +42 -0
  142. package/core/tera-system/teranoo-ui/components/page-header.tsx +25 -0
  143. package/core/tera-system/teranoo-ui/components/search-input.tsx +40 -0
  144. package/core/tera-system/teranoo-ui/components/sidebar.tsx +66 -0
  145. package/core/tera-system/teranoo-ui/components/stats-card.tsx +37 -0
  146. package/core/tera-system/teranoo-ui/registry.json +77 -0
  147. package/core/tera-system/teranoo-ui/styles/teranoo-theme.css +61 -0
  148. package/opencode.tera.example.json +30 -0
  149. package/package.json +37 -0
  150. package/scripts/build.mjs +110 -0
  151. package/scripts/install.js +244 -0
  152. package/scripts/lib/license.mjs +90 -0
  153. package/scripts/lib/public-key.pem +3 -0
  154. package/scripts/tera-license.mjs +63 -0
  155. package/tools/tera-clean.ps1 +97 -0
  156. package/tools/tera-fetch.ps1 +165 -0
  157. package/tools/tera-release.ps1 +96 -0
  158. package/tools/tera-schedule.ps1 +59 -0
  159. package/tools/tera-update.ps1 +472 -0
  160. package/tools/tera-watch.ps1 +154 -0
  161. package/tools/update-client-repositories.ps1 +92 -0
@@ -0,0 +1,66 @@
1
+ import * as React from "react"
2
+
3
+ interface SidebarItem {
4
+ label: string
5
+ icon?: React.ReactNode
6
+ href?: string
7
+ active?: boolean
8
+ children?: SidebarItem[]
9
+ }
10
+
11
+ interface SidebarProps {
12
+ items: SidebarItem[]
13
+ collapsed?: boolean
14
+ onToggle?: () => void
15
+ footer?: React.ReactNode
16
+ }
17
+
18
+ export function Sidebar({ items, collapsed, onToggle, footer }: SidebarProps) {
19
+ return (
20
+ <aside
21
+ className={`flex flex-col border-l border-[var(--teranoo-border)] bg-[var(--teranoo-background)] transition-all duration-300 ${
22
+ collapsed ? "w-16" : "w-64"
23
+ }`}
24
+ >
25
+ <div className="flex items-center justify-between p-4 border-b border-[var(--teranoo-border)]">
26
+ {!collapsed && (
27
+ <span className="font-semibold text-lg">Teranoo</span>
28
+ )}
29
+ <button
30
+ onClick={onToggle}
31
+ className="p-1 rounded-md hover:bg-[var(--teranoo-muted)]"
32
+ >
33
+ {collapsed ? "→" : "←"}
34
+ </button>
35
+ </div>
36
+
37
+ <nav className="flex-1 p-2 space-y-1">
38
+ {items.map((item, i) => (
39
+ <SidebarLink key={i} item={item} collapsed={collapsed} />
40
+ ))}
41
+ </nav>
42
+
43
+ {footer && (
44
+ <div className="p-4 border-t border-[var(--teranoo-border)]">
45
+ {footer}
46
+ </div>
47
+ )}
48
+ </aside>
49
+ )
50
+ }
51
+
52
+ function SidebarLink({ item, collapsed }: { item: SidebarItem; collapsed?: boolean }) {
53
+ return (
54
+ <a
55
+ href={item.href || "#"}
56
+ className={`flex items-center gap-3 px-3 py-2 rounded-[var(--teranoo-radius)] text-sm transition-colors ${
57
+ item.active
58
+ ? "bg-[var(--teranoo-primary)] text-[var(--teranoo-primary-foreground)]"
59
+ : "text-[var(--teranoo-foreground)] hover:bg-[var(--teranoo-muted)]"
60
+ }`}
61
+ >
62
+ {item.icon && <span className="h-4 w-4">{item.icon}</span>}
63
+ {!collapsed && <span>{item.label}</span>}
64
+ </a>
65
+ )
66
+ }
@@ -0,0 +1,37 @@
1
+ import * as React from "react"
2
+ import { Card, CardContent } from "./card"
3
+
4
+ interface StatsCardProps {
5
+ label: string
6
+ value: string | number
7
+ description?: string
8
+ trend?: "up" | "down" | "neutral"
9
+ }
10
+
11
+ export function StatsCard({ label, value, description, trend }: StatsCardProps) {
12
+ const trendIcon = trend === "up" ? "↑" : trend === "down" ? "↓" : "→"
13
+ const trendColor = trend === "up"
14
+ ? "text-[var(--teranoo-success)]"
15
+ : trend === "down"
16
+ ? "text-[var(--teranoo-danger)]"
17
+ : "text-[var(--teranoo-muted-foreground)]"
18
+
19
+ return (
20
+ <Card>
21
+ <CardContent className="p-4">
22
+ <div className="space-y-1">
23
+ <p className="text-xs text-[var(--teranoo-muted-foreground)]">{label}</p>
24
+ <div className="flex items-baseline gap-2">
25
+ <p className="text-2xl font-bold">{value}</p>
26
+ {trend && (
27
+ <span className={`text-sm ${trendColor}`}>{trendIcon}</span>
28
+ )}
29
+ </div>
30
+ {description && (
31
+ <p className="text-xs text-[var(--teranoo-muted-foreground)]">{description}</p>
32
+ )}
33
+ </div>
34
+ </CardContent>
35
+ </Card>
36
+ )
37
+ }
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "teranoo-ui",
3
+ "description": "Teranoo UI Registry — مكونات Tera المعتمدة لتطبيقات الزبائن",
4
+ "version": "1.0.0",
5
+ "registry": [
6
+ {
7
+ "name": "button",
8
+ "type": "components:ui",
9
+ "description": "زر Tera الأساسي — يمتد shadcn button مع ثيم Tera",
10
+ "dependencies": ["@radix-ui/react-slot"],
11
+ "files": ["components/button.tsx"]
12
+ },
13
+ {
14
+ "name": "card",
15
+ "type": "components:ui",
16
+ "description": "بطاقة Tera — تعرض محتوى بحدود وظل موحدين",
17
+ "dependencies": [],
18
+ "files": ["components/card.tsx"]
19
+ },
20
+ {
21
+ "name": "dashboard-layout",
22
+ "type": "components:ui",
23
+ "description": "هيكل لوحة تحكم كامل — Sidebar + Header + Main",
24
+ "dependencies": [],
25
+ "files": ["components/dashboard-layout.tsx"]
26
+ },
27
+ {
28
+ "name": "data-table",
29
+ "type": "components:ui",
30
+ "description": "جدول بيانات متقدم — فرز، فلتر، بحث، Pagination",
31
+ "dependencies": ["@tanstack/react-table"],
32
+ "files": ["components/data-table.tsx"]
33
+ },
34
+ {
35
+ "name": "kpi-card",
36
+ "type": "components:ui",
37
+ "description": "بطاقة KPI — عنوان، قيمة، مؤشر تغيير، أيقونة",
38
+ "dependencies": [],
39
+ "files": ["components/kpi-card.tsx"]
40
+ },
41
+ {
42
+ "name": "sidebar",
43
+ "type": "components:ui",
44
+ "description": "قائمة جانبية — عناصر قائمة مع أيقونات، قابلة للطي",
45
+ "dependencies": ["@radix-ui/react-dialog"],
46
+ "files": ["components/sidebar.tsx"]
47
+ },
48
+ {
49
+ "name": "stats-card",
50
+ "type": "components:ui",
51
+ "description": "بطاقة إحصائية — رقم، وصف، رسم بياني صغير",
52
+ "dependencies": [],
53
+ "files": ["components/stats-card.tsx"]
54
+ },
55
+ {
56
+ "name": "page-header",
57
+ "type": "components:ui",
58
+ "description": "عنوان صفحة موحّد — عنوان، وصف، أزرار إجراءات",
59
+ "dependencies": [],
60
+ "files": ["components/page-header.tsx"]
61
+ },
62
+ {
63
+ "name": "search-input",
64
+ "type": "components:ui",
65
+ "description": "حقل بحث موحّد — أيقونة، كتابة، مسح",
66
+ "dependencies": [],
67
+ "files": ["components/search-input.tsx"]
68
+ },
69
+ {
70
+ "name": "empty-state",
71
+ "type": "components:ui",
72
+ "description": "حالة عدم وجود بيانات — أيقونة، رسالة، زر إجراء",
73
+ "dependencies": [],
74
+ "files": ["components/empty-state.tsx"]
75
+ }
76
+ ]
77
+ }
@@ -0,0 +1,61 @@
1
+ /* ============================================
2
+ Teranoo Theme — ألوان Tera الموحّدة
3
+ استخدم هذا الملف في أي مشروع Tera UI
4
+ ============================================ */
5
+
6
+ :root {
7
+ /* الألوان الأساسية */
8
+ --teranoo-primary: #2563eb;
9
+ --teranoo-primary-foreground: #ffffff;
10
+ --teranoo-primary-hover: #1d4ed8;
11
+
12
+ --teranoo-secondary: #64748b;
13
+ --teranoo-secondary-foreground: #ffffff;
14
+
15
+ --teranoo-accent: #f59e0b;
16
+ --teranoo-accent-foreground: #1c1917;
17
+
18
+ --teranoo-success: #10b981;
19
+ --teranoo-warning: #f59e0b;
20
+ --teranoo-danger: #ef4444;
21
+ --teranoo-info: #3b82f6;
22
+
23
+ /* الخلفية والنص */
24
+ --teranoo-background: #ffffff;
25
+ --teranoo-foreground: #0f172a;
26
+ --teranoo-muted: #f1f5f9;
27
+ --teranoo-muted-foreground: #64748b;
28
+ --teranoo-border: #e2e8f0;
29
+ --teranoo-input: #e2e8f0;
30
+ --teranoo-ring: #2563eb;
31
+
32
+ /* الزوايا */
33
+ --teranoo-radius: 0.5rem;
34
+
35
+ /* الخطوط */
36
+ --teranoo-font-family: 'Cairo', 'Inter', sans-serif;
37
+ --teranoo-font-size-xs: 0.75rem;
38
+ --teranoo-font-size-sm: 0.875rem;
39
+ --teranoo-font-size-base: 1rem;
40
+ --teranoo-font-size-lg: 1.125rem;
41
+ --teranoo-font-size-xl: 1.25rem;
42
+ --teranoo-font-size-2xl: 1.5rem;
43
+
44
+ /* الظلال */
45
+ --teranoo-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
46
+ --teranoo-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
47
+ --teranoo-shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
48
+ --teranoo-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
49
+
50
+ /* RTL */
51
+ --teranoo-direction: rtl;
52
+ }
53
+
54
+ /* وضع الظلام (اختياري) */
55
+ .dark {
56
+ --teranoo-primary: #3b82f6;
57
+ --teranoo-background: #0f172a;
58
+ --teranoo-foreground: #f8fafc;
59
+ --teranoo-muted: #1e293b;
60
+ --teranoo-border: #334155;
61
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://opencode.ai/config.json",
3
+ "mcp": {
4
+ "playwright": {
5
+ "type": "local",
6
+ "command": ["npx", "-y", "@playwright/mcp"],
7
+ "enabled": true
8
+ },
9
+ "semgrep": {
10
+ "type": "local",
11
+ "command": ["npx", "-y", "mcp-server-semgrep"],
12
+ "enabled": true
13
+ },
14
+ "structurizr": {
15
+ "type": "local",
16
+ "command": [
17
+ "uv",
18
+ "run",
19
+ "--directory",
20
+ "structurizr-mcp",
21
+ "structurizr-mcp"
22
+ ],
23
+ "enabled": false,
24
+ "env": {
25
+ "STRUCTURIZR_WORKSPACE_DIR": "../architecture",
26
+ "STRUCTURIZR_URL": "http://localhost:8081"
27
+ }
28
+ }
29
+ }
30
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@tera-system/core",
3
+ "version": "0.1.0",
4
+ "description": "Tera System OpenCode Plugin — governance core, 20 agents, 10 commands, distribution tools",
5
+ "license": "SEE LICENSE IN LICENSE.md",
6
+ "type": "module",
7
+ "engines": {
8
+ "node": ">=18"
9
+ },
10
+ "files": [
11
+ "agents",
12
+ "commands",
13
+ "core",
14
+ "tools",
15
+ "scripts",
16
+ "MANIFEST.json",
17
+ "opencode.tera.example.json",
18
+ "WELCOME.md",
19
+ "README.md",
20
+ "LICENSE.md",
21
+ "RELEASES.md"
22
+ ],
23
+ "scripts": {
24
+ "postinstall": "node scripts/install.js"
25
+ },
26
+ "keywords": [
27
+ "opencode",
28
+ "plugin",
29
+ "tera",
30
+ "governance",
31
+ "agents",
32
+ "component"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ }
37
+ }
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @tera/core build script
4
+ * --------------------------------------------------------------
5
+ * Produces a repeatable, verifiable release artifact for the
6
+ * OpenCode addon. NON-DESTRUCTIVE: only (re)creates files under
7
+ * `artifacts/` and NEVER touches package source content.
8
+ *
9
+ * Steps:
10
+ * 1. Validate content counts against MANIFEST.json (self-check).
11
+ * 2. `npm pack` the current package -> artifacts/<name>-<version>.tgz
12
+ * 3. Compute per-content-group SHA256 + artifact SHA256.
13
+ * 4. Write artifacts/SHA256SUMS.txt (+ per-file group map).
14
+ *
15
+ * Usage:
16
+ * node scripts/build.mjs (default: version from package.json)
17
+ */
18
+ import { execSync } from "node:child_process";
19
+ import { createHash } from "node:crypto";
20
+ import fs from "node:fs";
21
+ import path from "node:path";
22
+ import { fileURLToPath } from "node:url";
23
+
24
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
25
+ const ROOT = path.resolve(__dirname, "..");
26
+ const ART = path.join(ROOT, "artifacts");
27
+
28
+ const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, "package.json"), "utf8"));
29
+ const manifest = JSON.parse(fs.readFileSync(path.join(ROOT, "MANIFEST.json"), "utf8"));
30
+
31
+ const countFiles = (dir) =>
32
+ fs.existsSync(path.join(ROOT, dir))
33
+ ? (function walk(d) {
34
+ let n = 0;
35
+ for (const e of fs.readdirSync(d, { withFileTypes: true })) {
36
+ if (e.isDirectory()) n += walk(path.join(d, e.name));
37
+ else if (e.isFile()) n++;
38
+ }
39
+ return n;
40
+ })(path.join(ROOT, dir))
41
+ : 0;
42
+
43
+ const groupSha = (dir) => {
44
+ if (!fs.existsSync(path.join(ROOT, dir))) return null;
45
+ const lines = [];
46
+ (function walk(d) {
47
+ for (const e of fs.readdirSync(d, { withFileTypes: true })) {
48
+ const full = path.join(d, e.name);
49
+ if (e.isDirectory()) walk(full);
50
+ else if (e.isFile()) {
51
+ const h = createHash("sha256").update(fs.readFileSync(full)).digest("hex");
52
+ lines.push(`${path.relative(ROOT, full).split(path.sep).join("/")}:${h}`);
53
+ }
54
+ }
55
+ })(path.join(ROOT, dir));
56
+ lines.sort();
57
+ return createHash("sha256").update(lines.join("\n")).digest("hex");
58
+ };
59
+
60
+ /* 1. self-check counts vs manifest */
61
+ console.log("── self-check: content counts vs MANIFEST.json");
62
+ const checks = [
63
+ ["agents", "agents"],
64
+ ["commands", "commands"],
65
+ ["core/tera-system", "coreFiles"],
66
+ ];
67
+ let fail = false;
68
+ for (const [dir, key] of checks) {
69
+ const n = countFiles(dir);
70
+ const expected = manifest.content[key];
71
+ const ok = n === expected;
72
+ console.log(` ${dir.padEnd(16)} ${n} (manifest ${expected}) ${ok ? "OK" : "MISMATCH"}`);
73
+ if (!ok) fail = true;
74
+ }
75
+ if (fail) {
76
+ console.error("✖ Self-check failed — aborting build.");
77
+ process.exit(1);
78
+ }
79
+
80
+ /* 2. pack */
81
+ console.log("── npm pack");
82
+ fs.mkdirSync(ART, { recursive: true });
83
+ const tarball = execSync(`npm pack ${JSON.stringify(ROOT)} --pack-destination ${JSON.stringify(ART)} --silent`, { cwd: ROOT, encoding: "utf8" }).trim();
84
+ console.log(` artifact: ${tarball}`);
85
+
86
+ /* 3. hashes */
87
+ const artPath = path.join(ART, tarball);
88
+ const artHash = createHash("sha256").update(fs.readFileSync(artPath)).digest("hex");
89
+ console.log(` SHA256 : ${artHash}`);
90
+
91
+ const groupHashes = {
92
+ agents: groupSha("agents"),
93
+ commands: groupSha("commands"),
94
+ "core/tera-system": groupSha("core/tera-system"),
95
+ tools: groupSha("tools"),
96
+ "core/project-control": groupSha("core/project-control"),
97
+ };
98
+ console.log(" group hashes:");
99
+ for (const [g, h] of Object.entries(groupHashes)) console.log(` ${g.padEnd(20)} ${h ?? "(n/a)"}`);
100
+
101
+ /* 4. write SHA256SUMS + group map + sync MANIFEST.json (single source of truth) */
102
+ fs.writeFileSync(path.join(ART, "SHA256SUMS.txt"), `${artHash} ${tarball}\n`);
103
+ fs.writeFileSync(path.join(ART, "GROUPS.json"), JSON.stringify({ version: pkg.version, builtAt: new Date().toISOString(), sha256: groupHashes }, null, 2));
104
+ manifest.sha256 = groupHashes;
105
+ manifest.version = pkg.version;
106
+ manifest.builtAt = new Date().toISOString().slice(0, 10);
107
+ fs.writeFileSync(path.join(ROOT, "MANIFEST.json"), JSON.stringify(manifest, null, 2) + "\n");
108
+ console.log(" wrote SHA256SUMS.txt + GROUPS.json + synced MANIFEST.json");
109
+
110
+ console.log("\n✔ build complete — artifact ready in artifacts/");
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @tera/core installer
4
+ * --------------------------------------------------------------
5
+ * NON-DESTRUCTIVE + OWNERSHIP-AWARE installer for the Tera System
6
+ * OpenCode Plugin component.
7
+ *
8
+ * Rules:
9
+ * - Never deletes anything.
10
+ * - Never overwrites a file it does not own.
11
+ * - Tracks ownership via `.opencode/tera-core.manifest.json`.
12
+ * - Only updates files it owns, always keeping a backup first.
13
+ * - Idempotent: re-running is safe; identical files are skipped.
14
+ * - Never touches an existing user `opencode.json`.
15
+ *
16
+ * Target resolution (first match wins):
17
+ * 1. `--target <dir>` argument
18
+ * 2. `TERA_TARGET_DIR` environment variable
19
+ * 3. `INIT_CWD` (set by npm for lifecycle scripts)
20
+ * 4. current working directory
21
+ */
22
+ import { createHash } from "node:crypto";
23
+ import fs from "node:fs";
24
+ import path from "node:path";
25
+ import { fileURLToPath } from "node:url";
26
+ import { assessLicenseState, readLicenseState, writeLicenseState } from "./lib/license.mjs";
27
+
28
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
29
+ const PKG_ROOT = path.resolve(__dirname, "..");
30
+ const MANIFEST_NAME = "tera-core.manifest.json";
31
+ const CONFIG_EXAMPLE = "opencode.tera.example.json";
32
+
33
+ /* ---------------------------------- helpers ---------------------------------- */
34
+
35
+ const sha256 = (buf) => createHash("sha256").update(buf).digest("hex");
36
+
37
+ const toPosix = (p) => p.split(path.sep).join("/");
38
+
39
+ function resolveTarget() {
40
+ const args = process.argv.slice(2);
41
+ for (let i = 0; i < args.length; i++) {
42
+ if (args[i] === "--help") {
43
+ console.log("Usage: node scripts/install.js [--target <workspaceRoot>]");
44
+ process.exit(0);
45
+ }
46
+ if (args[i] === "--target" && args[i + 1]) {
47
+ return path.resolve(args[i + 1]);
48
+ }
49
+ }
50
+ if (process.env.TERA_TARGET_DIR) return path.resolve(process.env.TERA_TARGET_DIR);
51
+ if (process.env.INIT_CWD) return path.resolve(process.env.INIT_CWD);
52
+ return path.resolve(process.cwd());
53
+ }
54
+
55
+ function walkFiles(dir) {
56
+ const out = [];
57
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
58
+ const full = path.join(dir, entry.name);
59
+ if (entry.isDirectory()) out.push(...walkFiles(full));
60
+ else if (entry.isFile()) out.push(full);
61
+ }
62
+ return out;
63
+ }
64
+
65
+ function copyFile(src, dest) {
66
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
67
+ fs.copyFileSync(src, dest);
68
+ }
69
+
70
+ function loadOwnership(target) {
71
+ const p = path.join(target, ".opencode", MANIFEST_NAME);
72
+ if (!fs.existsSync(p)) return { files: {} };
73
+ try {
74
+ const parsed = JSON.parse(fs.readFileSync(p, "utf8"));
75
+ return { files: parsed.files && typeof parsed.files === "object" ? parsed.files : {} };
76
+ } catch {
77
+ return { files: {} };
78
+ }
79
+ }
80
+
81
+ /* ---------------------------------- state ---------------------------------- */
82
+
83
+ const target = resolveTarget();
84
+ const pkg = JSON.parse(fs.readFileSync(path.join(PKG_ROOT, "package.json"), "utf8"));
85
+ const ownership = loadOwnership(target);
86
+
87
+ const stats = { installed: 0, updated: 0, identical: 0, skippedGroups: 0, conflicts: [] };
88
+
89
+ /* ------------------------------- group install ------------------------------- */
90
+
91
+ /**
92
+ * @param {{name:string, src:string, dest:string}} group
93
+ */
94
+ function installGroup(group) {
95
+ if (!fs.existsSync(group.src)) return;
96
+ for (const srcFile of walkFiles(group.src)) {
97
+ const relSrc = path.relative(group.src, srcFile);
98
+ const destFile = path.join(group.dest, relSrc);
99
+ const destRel = toPosix(path.relative(target, destFile));
100
+ const srcHash = sha256(fs.readFileSync(srcFile));
101
+
102
+ if (fs.existsSync(destFile)) {
103
+ const destHash = sha256(fs.readFileSync(destFile));
104
+ if (destHash === srcHash) {
105
+ stats.identical++;
106
+ continue;
107
+ }
108
+ const owned = Object.prototype.hasOwnProperty.call(ownership.files, destRel);
109
+ if (owned) {
110
+ const bak = `${destFile}.tera-bak-${Date.now()}`;
111
+ fs.copyFileSync(destFile, bak);
112
+ fs.copyFileSync(srcFile, destFile);
113
+ ownership.files[destRel] = srcHash;
114
+ stats.updated++;
115
+ console.log(` [updated ] ${destRel} (backup: ${path.basename(bak)})`);
116
+ } else {
117
+ stats.conflicts.push(destRel);
118
+ console.log(` [CONFLICT] ${destRel} — kept your file (unowned, not overwritten).`);
119
+ }
120
+ } else {
121
+ copyFile(srcFile, destFile);
122
+ ownership.files[destRel] = srcHash;
123
+ stats.installed++;
124
+ console.log(` [install ] ${destRel}`);
125
+ }
126
+ }
127
+ }
128
+
129
+ /* ---------------------------------- config ---------------------------------- */
130
+
131
+ function installConfig() {
132
+ const configSrc = path.join(PKG_ROOT, CONFIG_EXAMPLE);
133
+ if (!fs.existsSync(configSrc)) return;
134
+ const configDest = path.join(target, ".opencode", "opencode.json");
135
+ const configRel = ".opencode/opencode.json";
136
+
137
+ if (fs.existsSync(configDest)) {
138
+ const a = sha256(fs.readFileSync(configDest));
139
+ const b = sha256(fs.readFileSync(configSrc));
140
+ if (a === b) {
141
+ stats.identical++;
142
+ console.log(` [same ] ${configRel} — already identical.`);
143
+ } else {
144
+ stats.conflicts.push(configRel);
145
+ console.log(` [CONFLICT] ${configRel} — kept yours. Reference copy provided below.`);
146
+ }
147
+ } else {
148
+ copyFile(configSrc, configDest);
149
+ ownership.files[configRel] = sha256(fs.readFileSync(configDest));
150
+ stats.installed++;
151
+ console.log(` [install ] ${configRel}`);
152
+ }
153
+
154
+ // Additive reference copy — always written, never destructive.
155
+ const exampleDest = path.join(target, ".opencode", CONFIG_EXAMPLE);
156
+ copyFile(configSrc, exampleDest);
157
+ console.log(` [reference] .opencode/${CONFIG_EXAMPLE}`);
158
+ }
159
+
160
+ /* ------------------------------ project-control ------------------------------ */
161
+
162
+ function installProjectControl() {
163
+ const pcSrc = path.join(PKG_ROOT, "core", "project-control");
164
+ if (!fs.existsSync(pcSrc)) return;
165
+ const pcDest = path.join(target, "project-control");
166
+ if (fs.existsSync(pcDest)) {
167
+ stats.skippedGroups++;
168
+ console.log(" [SKIP ] project-control/ — exists (user-owned state). Skeleton not installed.");
169
+ return;
170
+ }
171
+ for (const f of walkFiles(pcSrc)) {
172
+ const relF = toPosix(path.relative(pcSrc, f));
173
+ const d = path.join(pcDest, relF);
174
+ copyFile(f, d);
175
+ ownership.files[`project-control/${relF}`] = sha256(fs.readFileSync(f));
176
+ stats.installed++;
177
+ console.log(` [install ] project-control/${relF}`);
178
+ }
179
+ }
180
+
181
+ /* ----------------------------------- run ----------------------------------- */
182
+
183
+ console.log(`\n@tera/core v${pkg.version} — install`);
184
+ console.log(` target workspace : ${target}\n`);
185
+
186
+ installGroup({ name: "agents", src: path.join(PKG_ROOT, "agents"), dest: path.join(target, ".opencode", "agents") });
187
+ installGroup({ name: "commands", src: path.join(PKG_ROOT, "commands"), dest: path.join(target, ".opencode", "commands") });
188
+ installGroup({ name: "tera-system", src: path.join(PKG_ROOT, "core", "tera-system"), dest: path.join(target, "tera-system") });
189
+ installGroup({ name: "tools", src: path.join(PKG_ROOT, "tools"), dest: path.join(target, "tools") });
190
+ installConfig();
191
+ installProjectControl();
192
+
193
+ /* -------------------------------- persist log -------------------------------- */
194
+
195
+ const manifest = {
196
+ name: pkg.name,
197
+ version: pkg.version,
198
+ installedAt: new Date().toISOString(),
199
+ target,
200
+ files: ownership.files,
201
+ conflicts: stats.conflicts,
202
+ summary: {
203
+ installed: stats.installed,
204
+ updated: stats.updated,
205
+ identical: stats.identical,
206
+ skippedGroups: stats.skippedGroups,
207
+ conflicts: stats.conflicts.length,
208
+ },
209
+ };
210
+
211
+ const manifestPath = path.join(target, ".opencode", MANIFEST_NAME);
212
+ fs.mkdirSync(path.dirname(manifestPath), { recursive: true });
213
+ fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
214
+
215
+ /* ------------------- license state (non-blocking, never breaks install) ------------------- */
216
+ try {
217
+ const stateFile = path.join(target, ".tera", "license.state.json");
218
+ let licenseKey = (readLicenseState(stateFile) || {}).licenseKey;
219
+ if (!licenseKey) licenseKey = process.env.TERA_LICENSE_KEY || undefined;
220
+ const state = assessLicenseState(licenseKey);
221
+ writeLicenseState(stateFile, {
222
+ state: state.state,
223
+ reason: state.reason,
224
+ licenseKey: licenseKey || null,
225
+ expiresAt: state.expiresAt || null,
226
+ checkedAt: new Date().toISOString(),
227
+ });
228
+ console.log(` [license ] state=${state.state} (${state.reason})`);
229
+ } catch (err) {
230
+ console.log(` [license ] skipped (${err.message}) — install continues`);
231
+ }
232
+
233
+ console.log("\n summary:");
234
+ console.log(` installed : ${stats.installed}`);
235
+ console.log(` updated : ${stats.updated}`);
236
+ console.log(` identical : ${stats.identical}`);
237
+ console.log(` conflicts : ${stats.conflicts.length} (your files kept untouched)`);
238
+ console.log(` skipped : ${stats.skippedGroups} group(s) — user-owned state`);
239
+ console.log(` ownership log : ${path.join(".opencode", MANIFEST_NAME)}\n`);
240
+
241
+ if (stats.conflicts.length > 0) {
242
+ console.log(" ⚠ conflicts — your files were kept. Review them before relying on Tera content.");
243
+ process.exitCode = 0;
244
+ }