@putdotio/taizn 1.3.0 → 1.5.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.
package/README.md CHANGED
@@ -46,6 +46,9 @@ Project files:
46
46
 
47
47
  ```bash
48
48
  taizn check
49
+ taizn apps
50
+ taizn apps put
51
+ taizn launch GinifYRGmZ.putio
49
52
  taizn profile
50
53
  taizn package
51
54
  taizn install
@@ -58,7 +61,9 @@ taizn --version
58
61
  ```
59
62
 
60
63
  `check` verifies the configured Tizen CLI and `sdb`, then prints connected
61
- targets without requiring `taizn.json`. `profile` imports
64
+ targets without requiring `taizn.json`. `apps` lists installed applications on
65
+ the target, with an optional query filter. `launch` starts an already-installed
66
+ application by exact application ID, exact name, or a unique query. `profile` imports
62
67
  `.taizn/certificates/author.p12` and
63
68
  `.taizn/certificates/distributor.p12` into a Tizen security profile.
64
69
  `package` builds and signs a `.wgt`. `install` packages and sideloads it.
package/dist/taizn.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { NodeRuntime, NodeServices } from "@effect/platform-node";
3
3
  import { Argument, CliError, Command, Flag } from "effect/unstable/cli";
4
- import { Console, Context, Effect, FileSystem, Layer, Schema, Stream } from "effect";
4
+ import { Console, Context, Effect, FileSystem, Layer, Option, Schema, Stream } from "effect";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { homedir } from "node:os";
7
7
  import { existsSync } from "node:fs";
@@ -57,6 +57,19 @@ var CommandFailed = class extends Schema.TaggedErrorClass()("CommandFailed", {
57
57
  return `Command failed: ${this.command} ${this.args.join(" ")}`;
58
58
  }
59
59
  };
60
+ var ApplicationNotFound = class extends Schema.TaggedErrorClass()("ApplicationNotFound", { query: Schema.String }) {
61
+ get message() {
62
+ return `No installed Tizen application matched "${this.query}".`;
63
+ }
64
+ };
65
+ var MultipleApplicationsMatched = class extends Schema.TaggedErrorClass()("MultipleApplicationsMatched", {
66
+ matches: Schema.Array(Schema.String),
67
+ query: Schema.String
68
+ }) {
69
+ get message() {
70
+ return `Multiple installed Tizen applications matched "${this.query}": ${this.matches.join(", ")}. Use the application ID.`;
71
+ }
72
+ };
60
73
  var PackageNotProduced = class extends Schema.TaggedErrorClass()("PackageNotProduced", { outputDir: Schema.String }) {
61
74
  get message() {
62
75
  return `No .wgt package was produced in ${this.outputDir}`;
@@ -80,6 +93,11 @@ var MultipleTargetsConnected = class extends Schema.TaggedErrorClass()("Multiple
80
93
  return `Multiple Tizen targets are connected: ${this.targets.join(", ")}. Set TAIZN_TARGET explicitly.`;
81
94
  }
82
95
  };
96
+ var MissingTizenTarget = class extends Schema.TaggedErrorClass()("MissingTizenTarget", {}) {
97
+ get message() {
98
+ return "No Tizen target is connected. Set TAIZN_TARGET or connect exactly one device.";
99
+ }
100
+ };
83
101
  var MissingTvRemoteHost = class extends Schema.TaggedErrorClass()("MissingTvRemoteHost", {}) {
84
102
  get message() {
85
103
  return "Samsung TV host is required. Set TAIZN_TV_HOST or TAIZN_TARGET.";
@@ -793,6 +811,32 @@ const runWidget = Effect.fn("runWidget")(function* ({ config, env }) {
793
811
  ], { env: yield* baseChildEnv() });
794
812
  yield* Console.log(`Launched ${variant.applicationId}`);
795
813
  });
814
+ const listInstalledApplications = Effect.fn("listInstalledApplications")(function* (env, query) {
815
+ const { applications: installedApplications, target } = yield* loadInstalledApplications(env);
816
+ const queryLabel = query?.trim();
817
+ const normalizedQuery = normalizeQuery(queryLabel);
818
+ const applications = installedApplications.filter((application) => matchesApplicationQuery(application, normalizedQuery));
819
+ const suffix = queryLabel ? ` matching "${queryLabel}"` : "";
820
+ yield* Console.log(`Installed Tizen applications${suffix} on ${target}:`);
821
+ if (applications.length === 0) {
822
+ yield* Console.log("none");
823
+ return;
824
+ }
825
+ for (const application of applications) yield* Console.log(`- ${application.name} (${application.applicationId})`);
826
+ });
827
+ const launchInstalledApplication = Effect.fn("launchInstalledApplication")(function* (env, query) {
828
+ const tizenPath = yield* resolveTizenCli(env);
829
+ const { applications, target } = yield* loadInstalledApplications(env);
830
+ const application = yield* resolveInstalledApplication(query, applications);
831
+ yield* run$1(tizenPath, [
832
+ "run",
833
+ "-p",
834
+ application.applicationId,
835
+ "-s",
836
+ target
837
+ ], { env: yield* baseChildEnv() });
838
+ yield* Console.log(`Launched ${application.name} (${application.applicationId}) on ${target}`);
839
+ });
796
840
  const resolveTizenCli = Effect.fn("resolveTizenCli")(function* (env) {
797
841
  return yield* requireFile(env.tizenCli ?? (yield* defaultTizenCli()), "Tizen CLI");
798
842
  });
@@ -971,6 +1015,71 @@ const resolveRunTarget = Effect.fn("resolveRunTarget")(function* (env, sdbPath)
971
1015
  }
972
1016
  if (devices.length > 1) return yield* MultipleTargetsConnected.make({ targets: devices.map((device) => device.id) });
973
1017
  });
1018
+ const resolveRequiredSdbTarget = Effect.fn("resolveRequiredSdbTarget")(function* (env, sdbPath) {
1019
+ if (env.target) return env.target;
1020
+ const devices = yield* listSdbDevices(sdbPath);
1021
+ if (devices.length === 1) {
1022
+ const device = devices[0];
1023
+ if (device) {
1024
+ yield* Console.log(`Using connected Tizen target: ${device.id}${device.label ? ` (${device.label})` : ""}`);
1025
+ return device.id;
1026
+ }
1027
+ }
1028
+ if (devices.length > 1) return yield* MultipleTargetsConnected.make({ targets: devices.map((device) => device.id) });
1029
+ return yield* MissingTizenTarget.make({});
1030
+ });
1031
+ const loadInstalledApplications = Effect.fn("loadInstalledApplications")(function* (env) {
1032
+ const sdbPath = yield* resolveSdb(env);
1033
+ if (env.target) yield* run$1(sdbPath, ["connect", env.target], { env: yield* baseChildEnv() });
1034
+ const target = yield* resolveRequiredSdbTarget(env, sdbPath);
1035
+ return {
1036
+ applications: parseInstalledApplications(yield* capture(sdbPath, [
1037
+ "-s",
1038
+ target,
1039
+ "shell",
1040
+ "0",
1041
+ "applist"
1042
+ ])),
1043
+ target
1044
+ };
1045
+ });
1046
+ const parseInstalledApplications = (output) => output.split("\n").flatMap((line) => {
1047
+ const match = line.match(/^\s*'([^']*)'\s+'([^']*)'\s*$/);
1048
+ const name = match?.[1]?.trim();
1049
+ const applicationId = match?.[2]?.trim();
1050
+ return name && applicationId ? [{
1051
+ applicationId,
1052
+ name
1053
+ }] : [];
1054
+ });
1055
+ const normalizeQuery = (query) => query?.trim().toLowerCase();
1056
+ const matchesApplicationQuery = (application, normalizedQuery) => !normalizedQuery || application.name.toLowerCase().includes(normalizedQuery) || application.applicationId.toLowerCase().includes(normalizedQuery);
1057
+ const resolveInstalledApplication = Effect.fn("resolveInstalledApplication")(function* (query, applications) {
1058
+ const queryLabel = query.trim();
1059
+ const normalizedQuery = normalizeQuery(queryLabel);
1060
+ if (!normalizedQuery) return yield* ApplicationNotFound.make({ query });
1061
+ const exactMatch = applications.find((application) => application.applicationId.toLowerCase() === normalizedQuery);
1062
+ if (exactMatch) return exactMatch;
1063
+ const exactNameMatches = applications.filter((application) => application.name.toLowerCase() === normalizedQuery);
1064
+ if (exactNameMatches.length === 1) {
1065
+ const [match] = exactNameMatches;
1066
+ if (match) return match;
1067
+ }
1068
+ if (exactNameMatches.length > 1) return yield* MultipleApplicationsMatched.make({
1069
+ matches: exactNameMatches.map((application) => `${application.name} (${application.applicationId})`),
1070
+ query: queryLabel
1071
+ });
1072
+ const matches = applications.filter((application) => matchesApplicationQuery(application, normalizedQuery));
1073
+ if (matches.length === 1) {
1074
+ const [match] = matches;
1075
+ if (match) return match;
1076
+ }
1077
+ if (matches.length > 1) return yield* MultipleApplicationsMatched.make({
1078
+ matches: matches.map((application) => `${application.name} (${application.applicationId})`),
1079
+ query: queryLabel
1080
+ });
1081
+ return yield* ApplicationNotFound.make({ query: queryLabel });
1082
+ });
974
1083
  const run$1 = Effect.fn("run")(function* (command, args, options) {
975
1084
  const paths = yield* getPaths();
976
1085
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
@@ -1028,6 +1137,12 @@ const taizn = Command.make("taizn", {}, () => withContext((context) => packageWi
1028
1137
  const check = Command.make("check", {}, () => Effect.gen(function* () {
1029
1138
  yield* checkTizen(yield* loadEnv());
1030
1139
  }));
1140
+ const apps = Command.make("apps", { query: Argument.string("query").pipe(Argument.optional) }, ({ query }) => Effect.gen(function* () {
1141
+ yield* listInstalledApplications(yield* loadEnv(), Option.getOrUndefined(query));
1142
+ }));
1143
+ const launch = Command.make("launch", { query: Argument.string("query") }, ({ query }) => Effect.gen(function* () {
1144
+ yield* launchInstalledApplication(yield* loadEnv(), query);
1145
+ }));
1031
1146
  const profile = Command.make("profile", {}, () => withContext((context) => createProfile(context)));
1032
1147
  const pack = Command.make("package", {}, () => withContext((context) => packageWidget(context).pipe(Effect.asVoid)));
1033
1148
  const install = Command.make("install", {}, () => withContext((context) => installWidget(context)));
@@ -1050,7 +1165,9 @@ const tv = Command.make("tv", {}).pipe(Command.withSubcommands([
1050
1165
  tvInfo
1051
1166
  ]));
1052
1167
  const command = taizn.pipe(Command.withSubcommands([
1168
+ apps,
1053
1169
  check,
1170
+ launch,
1054
1171
  profile,
1055
1172
  pack,
1056
1173
  install,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@putdotio/taizn",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "A tiny CLI companion for interacting with Tizen ecosystem.",
5
5
  "keywords": [
6
6
  "cli",