forgexa-cli 1.79.3__tar.gz → 1.80.1__tar.gz

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 (33) hide show
  1. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/PKG-INFO +1 -1
  2. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/__init__.py +1 -1
  3. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/agent_core.py +7 -1
  4. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/daemon.py +1 -1
  5. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/observability_contract.py +20 -14
  6. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/observability_evidence.py +3 -1
  7. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli.egg-info/PKG-INFO +1 -1
  8. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/pyproject.toml +1 -1
  9. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/README.md +0 -0
  10. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/_build_config.py +0 -0
  11. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/_local_bind.py +0 -0
  12. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/autoupgrade.py +0 -0
  13. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/aws_evidence.py +0 -0
  14. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/aws_logs_evidence.py +0 -0
  15. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/main.py +0 -0
  16. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/py.typed +0 -0
  17. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/runtime_evidence.py +0 -0
  18. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli/zcode_protocol.py +0 -0
  19. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli.egg-info/SOURCES.txt +0 -0
  20. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli.egg-info/dependency_links.txt +0 -0
  21. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli.egg-info/entry_points.txt +0 -0
  22. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli.egg-info/requires.txt +0 -0
  23. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/forgexa_cli.egg-info/top_level.txt +0 -0
  24. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/setup.cfg +0 -0
  25. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_auth_and_runtime_commands.py +0 -0
  26. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_autoupgrade.py +0 -0
  27. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_check_command.py +0 -0
  28. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_expiry_warnings_and_revoke.py +0 -0
  29. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_local_bind_commands.py +0 -0
  30. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_runtime_credentials.py +0 -0
  31. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_session_credentials.py +0 -0
  32. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_silent_install.py +0 -0
  33. {forgexa_cli-1.79.3 → forgexa_cli-1.80.1}/tests/test_upgrade_observability.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.79.3
3
+ Version: 1.80.1
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,2 +1,2 @@
1
1
  """forgexa-cli — Forgexa command-line client."""
2
- __version__ = "1.79.3"
2
+ __version__ = "1.80.1"
@@ -255,7 +255,7 @@ def _assess_implementation_contributions(contract: dict, report: object) -> dict
255
255
  key: implementation[key] for key in ("status", "evidence", "description", "files", "plan_revision")
256
256
  if key in implementation
257
257
  }}
258
- if row.get("plan_revision") is not None:
258
+ if row.get("plan_revision") is not None and implementation.get("status") != "covered":
259
259
  check["plan_revision"] = row["plan_revision"]
260
260
  checks.append(check)
261
261
  if implementation.get("status") == "covered" and row.get("status") == "gap":
@@ -333,6 +333,12 @@ def assess_implementation_audit(contract: dict, report: object) -> dict:
333
333
  ):
334
334
  issues.append(f"Implementation {kind} check requires an explicit status and concrete evidence")
335
335
  continue
336
+ if status == "covered" and row.get("plan_revision") is not None:
337
+ issues.append(
338
+ "A covered implementation check cannot request a plan revision; "
339
+ "report the affected check as gap, blocked, or unverified"
340
+ )
341
+ continue
336
342
  if kind == "task":
337
343
  task_id = row.get("task_id")
338
344
  if not isinstance(task_id, str) or task_id not in expected or task_id in checked:
@@ -1234,7 +1234,7 @@ except (ImportError, ModuleNotFoundError):
1234
1234
  # DAEMON_VERSION is the protocol/logic version of the daemon code.
1235
1235
  # Kept in sync with pyproject.toml version via bump-version.sh.
1236
1236
  # CLIENT_TYPE identifies which packaging/distribution this daemon runs in.
1237
- DAEMON_VERSION = "1.79.3"
1237
+ DAEMON_VERSION = "1.80.1"
1238
1238
 
1239
1239
 
1240
1240
  def _detect_client_type() -> str:
@@ -9,7 +9,6 @@ def _strict_zip(*iterables):
9
9
  if any((item is missing for item in items)):
10
10
  raise ValueError('zip() arguments have different lengths')
11
11
  yield items
12
- import pycountry
13
12
  from pydantic import BaseModel
14
13
  from pydantic import ConfigDict
15
14
  import math
@@ -24,6 +23,7 @@ from pydantic import model_serializer
24
23
  from pydantic import model_validator
25
24
  import json
26
25
  from datetime import datetime
26
+ _ISO_COUNTRY_CODES = frozenset(('AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AO', 'AQ', 'AR', 'AS', 'AT', 'AU', 'AW', 'AX', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH', 'BI', 'BJ', 'BL', 'BM', 'BN', 'BO', 'BQ', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY', 'BZ', 'CA', 'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU', 'CV', 'CW', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG', 'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'GA', 'GB', 'GD', 'GE', 'GF', 'GG', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT', 'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IM', 'IN', 'IO', 'IQ', 'IR', 'IS', 'IT', 'JE', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM', 'KN', 'KP', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS', 'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'ME', 'MF', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN', 'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA', 'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA', 'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY', 'QA', 'RE', 'RO', 'RS', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI', 'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'SS', 'ST', 'SV', 'SX', 'SY', 'SZ', 'TC', 'TD', 'TF', 'TG', 'TH', 'TJ', 'TK', 'TL', 'TM', 'TN', 'TO', 'TR', 'TT', 'TV', 'TW', 'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN', 'VU', 'WF', 'WS', 'YE', 'YT', 'ZA', 'ZM', 'ZW'))
27
27
  Provider = Literal['mpulse', 'newrelic']
28
28
  ResultType = Literal['summary', 'table', 'timeseries', 'histogram', 'distribution', 'records', 'span', 'trace', 'metadata']
29
29
  Identifier = Annotated[str, Field(min_length=1, max_length=256, pattern='^[A-Za-z0-9_.:/-]+$')]
@@ -38,7 +38,7 @@ def unique_values(values: list) -> list:
38
38
  return values
39
39
 
40
40
  def validate_country_code(country: str) -> str:
41
- if len(country) != 2 or not country.isupper() or pycountry.countries.get(alpha_2=country) is None:
41
+ if len(country) != 2 or not country.isupper() or country not in _ISO_COUNTRY_CODES:
42
42
  raise ValueError('Invalid ISO country code')
43
43
  return country
44
44
 
@@ -192,7 +192,7 @@ class ObservabilityOrigin(ObservabilityModel):
192
192
  _validate_issuer = field_validator('issuer')(validate_issuer)
193
193
 
194
194
  class ObservabilityCoverageWindow(ObservabilityWindow):
195
- window_index: int = Field(default=0, ge=0, le=4, strict=True)
195
+ window_index: int = Field(default=0, ge=0, le=119, strict=True)
196
196
 
197
197
  class ObservabilitySource(ObservabilityModel):
198
198
  source_id: Identifier
@@ -200,7 +200,7 @@ class ObservabilitySource(ObservabilityModel):
200
200
  connection_id: Identifier
201
201
  environment: Identifier
202
202
  endpoint_region: Identifier
203
- scope_precision: Literal['dedicated', 'filtered']
203
+ scope_precision: Literal['dedicated', 'filtered', 'account']
204
204
  origin_scope_ids: list[Identifier] = Field(min_length=1, max_length=100)
205
205
  market_codes: list[str] = Field(default_factory=list, max_length=20)
206
206
  application_id: Union[Identifier, None] = None
@@ -251,12 +251,18 @@ class ObservabilitySafeParameters(ObservabilityModel):
251
251
  limit: Union[int, None] = Field(default=None, ge=1, le=5000, strict=True)
252
252
  interval_seconds: Union[int, None] = Field(default=None, ge=1, strict=True)
253
253
  workload_ids: Union[list[Identifier], None] = Field(default=None, min_length=1, max_length=1)
254
+ time_bucket: Union[Literal['day'], None] = None
255
+ timezone: Union[str, None] = Field(default=None, max_length=128)
254
256
 
255
257
  @model_serializer(mode='wrap')
256
258
  def serialize_optional_workloads(self, handler):
257
259
  value = handler(self)
258
260
  if self.workload_ids is None:
259
261
  value.pop('workload_ids', None)
262
+ if self.time_bucket is None:
263
+ value.pop('time_bucket', None)
264
+ if self.timezone is None:
265
+ value.pop('timezone', None)
260
266
  return value
261
267
 
262
268
  @field_validator('filters', mode='before')
@@ -319,7 +325,7 @@ class ObservabilityMetricValue(ObservabilityWindow):
319
325
  target_ref: Union[Identifier, None] = None
320
326
  scope_id: Identifier
321
327
  workload_id: Union[Identifier, None] = None
322
- window_index: int = Field(default=0, ge=0, le=4, strict=True)
328
+ window_index: int = Field(default=0, ge=0, le=119, strict=True)
323
329
  metric_id: Identifier
324
330
  definition_version: int = Field(ge=1, strict=True)
325
331
  data_type: Identifier
@@ -354,7 +360,7 @@ class ObservabilityRow(ObservabilityModel):
354
360
  kind: Literal['row', 'metadata']
355
361
  item_id: Identifier
356
362
  target_ref: Identifier
357
- window_index: int = Field(default=0, ge=0, le=4, strict=True)
363
+ window_index: int = Field(default=0, ge=0, le=119, strict=True)
358
364
  values: dict[Identifier, CellValue] = Field(min_length=1, max_length=50)
359
365
 
360
366
  class ObservabilityTimeBucket(ObservabilityWindow):
@@ -367,7 +373,7 @@ class ObservabilitySeries(ObservabilityModel):
367
373
  kind: Literal['series']
368
374
  item_id: Identifier
369
375
  target_ref: Identifier
370
- window_index: int = Field(default=0, ge=0, le=4, strict=True)
376
+ window_index: int = Field(default=0, ge=0, le=119, strict=True)
371
377
  field_id: Identifier
372
378
  dimensions: dict[Identifier, CellValue] = Field(default_factory=dict, max_length=10)
373
379
  native_unit: str = Field(min_length=1, max_length=128)
@@ -399,7 +405,7 @@ class ObservabilityHistory(ObservabilityModel):
399
405
  kind: Literal['history'] = 'history'
400
406
  item_id: Identifier
401
407
  target_ref: Identifier
402
- window_index: int = Field(default=0, ge=0, le=4, strict=True)
408
+ window_index: int = Field(default=0, ge=0, le=119, strict=True)
403
409
  field_id: Identifier
404
410
  axis: Literal['sample_index'] = 'sample_index'
405
411
  data_timezone: Union[str, None] = Field(default=None, max_length=128)
@@ -449,7 +455,7 @@ class ObservabilityDistribution(ObservabilityModel):
449
455
  kind: Literal['distribution']
450
456
  item_id: Identifier
451
457
  target_ref: Identifier
452
- window_index: int = Field(default=0, ge=0, le=4, strict=True)
458
+ window_index: int = Field(default=0, ge=0, le=119, strict=True)
453
459
  field_id: Identifier
454
460
  measurement_unit: str = Field(min_length=1, max_length=128)
455
461
  native_unit: Union[str, None] = Field(default=None, min_length=1, max_length=128)
@@ -470,7 +476,7 @@ class ObservabilitySpan(ObservabilityModel):
470
476
  kind: Literal['span']
471
477
  item_id: Identifier
472
478
  target_ref: Identifier
473
- window_index: int = Field(default=0, ge=0, le=4, strict=True)
479
+ window_index: int = Field(default=0, ge=0, le=119, strict=True)
474
480
  trace_id: Identifier
475
481
  span_id: Identifier
476
482
  parent_span_id: Union[Identifier, None] = None
@@ -481,7 +487,7 @@ class ObservabilityRedactedItem(ObservabilityModel):
481
487
  kind: Literal['redacted']
482
488
  item_id: Identifier
483
489
  target_ref: Identifier
484
- window_index: int = Field(default=0, ge=0, le=4, strict=True)
490
+ window_index: int = Field(default=0, ge=0, le=119, strict=True)
485
491
  original_kind: Literal['metric', 'series', 'history', 'distribution', 'span']
486
492
  value_scope: Literal['whole_field_structure']
487
493
  quality: Union[ObservabilityMetricQuality, None] = None
@@ -523,7 +529,7 @@ class ObservabilitySnapshotPayload(ObservabilityModel):
523
529
  scope: ObservabilityFrozenScope
524
530
  sources: list[ObservabilitySource] = Field(min_length=1, max_length=100)
525
531
  parameters: ObservabilitySafeParameters
526
- requested_windows: list[ObservabilityWindow] = Field(min_length=1, max_length=5)
532
+ requested_windows: list[ObservabilityWindow] = Field(min_length=1, max_length=120)
527
533
  actual_windows: list[ObservabilityCoverageWindow] = Field(default_factory=list, max_length=500)
528
534
  columns: list[ObservabilityColumn] = Field(min_length=1, max_length=50)
529
535
  data: list[DataItem] = Field(max_length=50000)
@@ -550,11 +556,11 @@ class ObservabilitySnapshotPayload(ObservabilityModel):
550
556
  for country in source.market_codes:
551
557
  validate_country_code(country)
552
558
  if self.integration_type == 'mpulse':
553
- if not source.application_id or source.account_id is not None or source.entity_guid:
559
+ if not source.application_id or source.account_id is not None or source.entity_guid or (source.scope_precision == 'account'):
554
560
  raise ValueError('observability_source_identity_invalid')
555
561
  if source.endpoint_region != 'mpulse.soasta.com':
556
562
  raise ValueError('observability_source_region_invalid')
557
- elif source.application_id or source.account_id is None or (not source.entity_guid):
563
+ elif source.application_id or source.account_id is None or (source.scope_precision != 'account' and (not source.entity_guid)):
558
564
  raise ValueError('observability_source_identity_invalid')
559
565
  elif source.endpoint_region not in {'US', 'EU', 'JP'}:
560
566
  raise ValueError('observability_source_region_invalid')
@@ -26,7 +26,9 @@ def _contract():
26
26
  f"{__package__}.observability_contract" if __package__ else "observability_contract"
27
27
  )
28
28
  serialization = module
29
- except ImportError:
29
+ except ImportError as error:
30
+ if getattr(error, "name", None) in {"pydantic", "pydantic_core"}:
31
+ raise EvidenceError("observability_evidence_runtime_dependency_missing") from None
30
32
  raise EvidenceError("observability_evidence_protocol_unsupported") from None
31
33
  return (
32
34
  module.ObservabilityEvidenceReference, module.ObservabilityAttachmentMetadata,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: forgexa-cli
3
- Version: 1.79.3
3
+ Version: 1.80.1
4
4
  Summary: Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform
5
5
  Author-email: Jason Sun <dev.winds@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "forgexa-cli"
3
- version = "1.79.3"
3
+ version = "1.80.1"
4
4
  description = "Forgexa CLI — command-line client and AI agent runtime for the Forgexa platform"
5
5
  requires-python = ">=3.9"
6
6
  license = "MIT"
File without changes
File without changes